Task.Run and UI Progress Updates - c#

This code snippet is from Stephen Cleary's blog and gives an example of how to report progress when using Task.Run. I would like to know why there are no cross thread issues with updating the UI, by which I mean why is invoke not required?
private async void button2_Click(object sender, EventArgs e)
{
var progressHandler = new Progress<string>(value =>
{
label2.Text = value;
});
var progress = progressHandler as IProgress<string>;
await Task.Run(() =>
{
for (int i = 0; i != 100; ++i)
{
if (progress != null)
progress.Report("Stage " + i);
Thread.Sleep(100);
}
});
label2.Text = "Completed.";
}

Progress<T> catches the current SynchronisationContext when it is instantiated. Whenever you call Report, it secretly delegates that to the captured context. In the example, the captured context is the UI, meaning that no exceptions occur.

The Progress<T> constructor captures the current SynchronizationContext object.
The SynchronizationContext class is a facility that abstracts the particulars of the involved threading model. That is, in Windows Forms it will use Control.Invoke, in WPF it will use Dispatcher.Invoke, etc.
When the progress.Report object is called, the Progress object itself knows that it should run its delegate using the captured SynchronizationContext.
In other terms, it works because Progress has been designed to handle that without the developer having to explicitly say it.

It seems you're confused due the fact that part of this cross-thread machinery is hidden from developer eyes so you just have to "take and use": https://devblogs.microsoft.com/dotnet/async-in-4-5-enabling-progress-and-cancellation-in-async-apis
We introduced the IProgress interface to enable you to create an
experience for displaying progress. This interface exposes a Report(T)
method, which the async task calls to report progress. You expose this
interface in the signature of the async method, and the caller must
provide an object that implements this interface. Together, the task
and the caller create a very useful linkage (and could be running on
different threads).
We also provided the Progress class, which is an implementation of
IProgress. You are encouraged to use Progress in your
implementation, because it handles all the bookkeeping around saving
and restoring the synchronization context. Progress exposes both an
event and an Action callback, which are called when the task
reports progress. This pattern enables you to write code that simply
reacts to progress changes as they occur. Together, IProgress and
Progress provide an easy way to pass progress information from a
background task to the UI thread.
Just one more thing to mention: progress notification will be invoked after the part of the job is done, not just at that moment. So, if your UI thread is idling and you have spare CPU core the delay will be almost zero. If your UI thread is busy, the notification will not be invoked until the moment the UI thread is back to idle (regardless how much spare CPU cores your computer has).

Related

Update UI while Task.Run or TaskFactory.StartNew is still working

So I have decided to rewrite my Mail client in WPF as I think it's about time I move on from Windows Forms (I still like it), but I am facing a bit of a problem.
I use a BackgroundWorker in my Windows Forms app to do stuff and in a foreach I worker.ReportProgress(currentProgress); and this allows me to update the UI as things are being done in the background which is great.
But just now after starting a new WPF project, I notice that there is no BackgroundWorker in the Toolbox (for WPF apps) so I go searching online, and found that some people have problems updating the UI while using BackgroundWorker with WPF. So this makes me think that using BackgroundWorker in a WPF app is a bit hacky - and I don't want that.
On that same page, another user refers them to this page, telling them to use Task.Run instead of BackgroundWorker in WPF. Upon looking at Task.Run docs, I immediately see how it can be useful, however I do have one concern. I do not see a way to "Report Progress" or to update the UI as things are being done. All I see is how to Run a Task and "await" it; leaving me with just one option - update the UI after the long-running Task has completed.
How can we update the UI of a WPF desktop app while Task.Run/TaskFactory.StartNew is still working?
You can stick with BackroundWorker if you so choose. There is nothing really hacky about it although it is very old-school. As others said, if you can't find it in your toolbox, you can always declare and initialise it straight from your code (don't forget the using System.ComponentModel; directive).
Stephen Cleary has an excellent series of blog posts on BackgroundWorker vs Task, which highlights the differences and limitations of each approach. It's definitely worth a read if you're on the fence or just curious.
http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html
If you do decide to go down the Task + async/await route, there are a couple of things specifically related to progress reporting that you should keep in mind.
Generally you should be aiming to have your await Task.Run encapsulate the smallest meaningful amount of work possible. The rest of your async method will then execute on the dispatcher SynchronizationContext (assuming that it was started on the dispatcher thread) and will be able to update the UI directly, like so:
List<object> items = GetItemsToProcess();
int doneSoFar = 0;
foreach (var item in items)
{
await Task.Run(() => SomeCpuIntensiveWorkAsync(item));
doneSoFar++;
int progressPercentage = (int)((double)doneSoFar / items.Count * 100);
// Update the UI.
this.ProgressBar.Value = progressPercentage;
}
This is the easiest way of implementing progress reporting in the async world.
The only time I can imagine reporting the progress from within the body of the delegate you pass to Task.Run is when you're processing a very large number of items, and the processing of each item takes a very short time (we're talking 10,000 items per second as a rough guide). In such a scenario creating a large number of extremely fine-grained Tasks and awaiting them will introduce significant overhead. If this is your case you can fall back to the progress reporting mechanism introduced in .NET 4: Progress<T>/IProgress<T>. It's quite similar to the way the BackgroundWorker reports progress (in that it relies on events) and it provides a bit more flexibility in terms of deciding when you get to post back to the dispatcher context.
public async Task DoWorkAsync()
{
// Let's assume we're on the UI thread now.
// Dummy up some items to process.
List<object> items = GetItemsToProcess();
// Wire up progress reporting.
// Creating a new instance of Progress
// will capture the SynchronizationContext
// any any calls to IProgress.Report
// will be posted to that context.
Progress<int> progress = new Progress<int>();
progress.ProgressChanged += (sender, progressPercentage) =>
{
// This callback will run on the thread which
// created the Progress<int> instance.
// You can update your UI here.
this.ProgressBar.Value = progressPercentage;
};
await Task.Run(() => this.LongRunningCpuBoundOperation(items, progress));
}
private void LongRunningCpuBoundOperation(List<object> items, IProgress<int> progress)
{
int doneSoFar = 0;
int lastReportedProgress = -1;
foreach (var item in items)
{
// Process item.
Thread.Sleep(1);
// Calculate and report progress.
doneSoFar++;
var progressPercentage = (int)((double)doneSoFar / items.Count * 100);
// Only post back to the dispatcher SynchronizationContext
// if the progress percentage actually changed.
if (progressPercentage != lastReportedProgress)
{
// Note that progress is IProgress<int>,
// not Progress<int>. This is important
// because Progress<int> implements
// IProgress<int>.Report explicitly.
progress.Report(progressPercentage);
lastReportedProgress = progressPercentage;
}
}
}

DoEvents vs anything else --> for long COM operation

I have a WPF program where my model need to load a "Out-of-Proc" (.exe) COM component in order to achieve some validations when a user make an action on the UI. I'd like to inform the user that a long action will take place to let him know that the application is busy, not just frozen. But any action on the UI does occur after the COM action is completed.
I think that any COM communication should be done on the main UI thread. It eliminates any solution that would run on another thread than the main (UI) thread.
I tried many options without success:
MSDN Dispatcher.PushFrame (DoEvents)
StackOverflow HCL (PushFrame)
Jason programming Blog (PushFrame)
I can't see how I can achieve a synchronous action from a model where I would need to refresh the UI.
My action has a property "IsLoading" that I subscribe from my view and where I try to update the UI according to its state but it seems that is not possible in WPF ???
Any other suggestions ?
Can I use async/await and do my COM action from another thread running another dispatcher (kind of complex) and will loose required synchronicity (user need results of COM operation to continue its work) ?
Mainly for Blindy...
Some clearer explications (more details about required synchronicity):
When a user click on a TreeView item, I load a grid then need to verify that data entered in the grid is still valid. To do validation, I need to load an application through COM and automate it to load a document, then parse it and verify the data in the grid (in the Model of the Grid in the view). That takes 10 seconds.
If I do that on another thread, then user can do an action to select to add a new row in the grid which still depends on the same COM application loaded with the previous document. I still need to wait for the application to load. It is a synchronous action. My application depends on that COM application with its loaded document to be in valid state for user to take more actions. But I need to give user some feedback on what I’m doing (start COM app and load on document). Doing COM action on another thread just report the problem later but do not solve the fact that user need to wait that the action would complete. I think I need to (force) update my WPF app but can’t find any (twisted) way to do it.
[UPDATE] As the OP has updated the question and specified he's using out-of-proc COM objects, the custom STA thread plumbing described below doesn't make sense. Now, a simple await Task.Run(() => { /* call the out-of-proc COM */}) is enough to keep the UI responsive. Kudos to #acelent for clarifying this point.
Recently I answered a related question: StaTaskScheduler and STA thread message pumping.
The solution was to create and use STA COM objects on a dedicated background STA thread which provides both message pumping and thread affinity for those COM objects.
I'd like to show how ThreadWithAffinityContext can be used in your case, with async/await:
dynamic _comObject = null;
ThreadWithAffinityContext _staThread = null;
// Start the long-running task
Task NewCommandHandlerAsync()
{
// create the ThreadWithAffinityContext if haven't done this yet
if (_staThread == null)
_staThread = new ThreadWithAffinityContext(
staThread: true,
pumpMessages: true);
// create the COM Object if haven't done this yet
if (_comObject == null)
{
await _staThread.Run(() =>
{
// _comObject will live on a dedicated STA thread,
// run by ThreadWithAffinityContext
_comObject = new ComObject();
}, CancellationToken.None);
}
// use the COM object
await _staThread.Run(() =>
{
// run a lengthy process
_comObject.DoWork();
}, CancellationToken.None);
}
// keep track of pending NewCommandHandlerAsync
Task _newCommandHandler = null;
// handle a WPF command
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{
// avoid re-entrancy (i.e., running two NewCommandHandlerAsync in parallel)
if (_newCommandHandler != null)
throw new InvalidOperationException("One NewCommandHandlerAsync at a time!");
try
{
await _newCommandHandler = NewCommandHandlerAsync();
}
finally
{
_newCommandHandler = null;
}
}
catch (Exception ex)
{
// handle all exceptions possibly thrown inside "async void" method
MessageBox.Show(ex.Message);
}
}
The fact that we have offloaded the lengthy process _comObject.DoWork() to a separate thread doesn't automatically solve the other common UI-related problem:
How to handle the UI when the lengthy background operation is pending?
There is a number of options. E.g., you can disable the UI elements which fire NewCommand_Executed event, to avoid re-entrancy, and enable another UI element to allow the user to cancel the pending work (a Stop button). You should also provide some progress feedback, if your COM object supports that.
Alternatively, you can display a modal dialog before staring the long-running task and hide it when the task has completed. As far as the UI usability goes, modality is less desirable, but it's very easy to implement (example).
You can create and use COM objects on any thread, the marshaller will take care of running it on a background thread if your application uses the STA threading model. There's no need to funnel every call through the main UI thread.
As to your last question in comments, since you'll be running this on a background thread, you of course need to synchronize like usual with lock and Invoke the result back on the main thread when done. This is nothing specially related to COM, it's just how Windows threading works.
In short, stop using the UI thread for heavy duty, non-UI related work.
I used this once for WPF so as to force the screen to re-Paint :
I used auto-translation from VB so I hope it's correct
private Action EmptyDelegate = () => { };
[System.Runtime.CompilerServices.Extension()]
public void Refresh(UIElement uiElement)
{
uiElement.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, EmptyDelegate);
}

Asynchronous Threading

I would please like to know where I can get an example of multithreading or asynchronous threading.
In the application that I am busy with I have to run a thread in the background of my application to fetch a value that is changing. And whenever this value reaches a certain amount then it needs to call another function. All this has to run in the background of the program so that the user can still do something else on the application.
Any examples or links that could help would really be appreciated.
In order to summarize the options, I will try to list them here (maybe it would be a good idea to make this a community wiki).
First of all, you can simply start a function in another thread:
Thread t = new Thread( ThreadProc );
t.Start();
// now you can wait for thread to finish with t.Join() or just continue
// Thread.IsBackground allows to control how thread lifetime influences
// the lifetime of the application
...
static void ThreadProc() {...} // can also be non-static, but for simplicity....
Then you can use BackgroundWorker:
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += MyFunction;
bgWorker.RunWorkerAsync();
voud MyFunction(object o, DoWorkEventArgs args) {...}
You can use ProgressChanged and RunWorkerCompleted events for more control (as well as WorkerReportsProgress and other properties)
Another option is to use ThreadPool, if your method will not take too much time:
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
...
static void ThreadProc(Object stateInfo) { ... }
Yet another option is to call BeginInvoke on a delegate:
public delegate int MyDelegate(...);
MyDelegate del = SomeFunction;
IAsyncResult ar = del.BeginInvoke(...);
int result = del.EndInvoke(ar);
This will execute on a thread from the thread pool. If you need to wait on calling thread, you can use IAsyncResult.IsCompleted, but it will block the calling thread.
And of course, you can use Task:
var task = Task.Factory.StartNew(() => MyMethod());
This will also execute MyMethod on a thread from the thread pool, so the same warnings apply (although you can use TaskCreationOptions.LongRunning to ensure that the new thread is always created). Under some circumstances (when you wait on task) it can even execute on the same thread, but it is well optimized so you should not worry about that.
This is probably the option with best tradeoff of simplicity vs control (of course, there is no really 'the best'). Here are the benefits (shamelessly stolen from Jon Skeet's answer):
Adding continuations (Task.ContinueWith)
Waiting for multiple tasks to complete (either all or any)
Capturing errors in the task and interrogating them later
Capturing cancellation (and allowing you to specify cancellation to start with)
Potentially having a return value
Using await in C# 5
Better control over scheduling (if it's going to be long-running, say so when you create the task so the task scheduler can take that into account)
Well depending on the level of control that you seek a BackgroundWorker could easily work and its found within the System.ComponentModel.BackgroundWorker. Now here is a link to the MSDN docs on the subject matter : http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
a Simple usecase secenario is like so:
BackgrouWorker BG = new BackgroudWorker();
GB.DoWork += YourFunctionDelegate(object Sender, EventArgs e);
GB.RunWorkerAsync();
Now YourFunctionDelegate(object Sender,EventArgs e) should be what ever it is you want run in the background. However needs to follow this argument form, There are also a good amount of helper functions associated with the backgroundworker like onProgressChanged event that allows monitoring of obviously progress, which if you are new to threading can prove to be a pain at first if you try to make your own threads.
If you would like more control over execution and how the threads function you should take a look at the Task-Parallel-Library here: http://msdn.microsoft.com/en-us/library/dd460717.aspx Which has copious amount of information about multi-threading.
Also here is a great tutorial on how to create a C# thread: http://support.microsoft.com/default.aspx?scid=kb;en-us;815804
For an overview of asynchronous programming on Windows 8 in .Net 4.5:
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
For .Net 4.0 and older you can use the ThreadPool
System.Threading.ThreadPool.QueueUserWorkItem(obj =>
{
// Do some work
for (int i = 0; i < 1000; i++)
Math.Sin(i);
// Get back to the UI thread
App.Current.MainWindow.Dispatcher.BeginInvoke(
new Action(delegate
{
block.Text = "Done!";
}));
});
I have a blog post that compares and contrasts various implementations of background tasks, with advantages and disadvantages for each. Spoiler: Task is definitely the best option. Also, I recommend Task.Run over TaskFactory.StartNew.
If your background operation is truly asynchronous, then you may not need any background threading at all. LINQPad has a set of async examples that are a great starting point. These are more up-to-date than the chapter on threading (by the same author) that others have recommended.

How do I make my application wait for my UI to refresh?

Without using extra threads I would simply like to display a "Loading" label or something similar to the user when a large amount of data is being read or written. If I however attempt to modify any UI elements before calling the IO method, the application freezes for a while and then displays the "Loading" message after all the work is already done. This obviously doesn't help. How can I ensure that any UI changes are applied and visible before calling the IO method?
DataSet ds = STT_Import.ImportExcelToDataSet(filePath);
bool result = false;
if (ds != null)
{
int cellCount = ds.GetTotalCellCount();
if (Popup.ShowMessage(string.Format("Your file contains {0} cells. Inserting data will take approximately {1} seconds. Do you want to continue?",
cellCount, CalculateTime(cellCount)), "Confirm", MessageType.Confirm) == MessageBoxResult.Yes)
{
// Tell user the application is working:
StatusLabel.Content = "Writing to database...";
// Do actual work after user has been notified:
result = DB.StoreItems(_currentType, ds);
}
}
I tried looking for answers but couldn't find anything that answered my specific question, so I'm sorry if the question has been asked before.
When working with WPF, you can use the Dispatcher to queue commands on the UI thread at different DispatcherPriorities
This will allow you to queue your long-running process on the UI thread after everything in the DispatcherPriority.Render or DispatcherPriority.Loaded queues have occurred.
For example, your code may look like this:
// Tell user the application is working:
StatusLabel.Content = "Writing to database...";
// Do actual work after user has been notified:
Dispatcher.BeginInvoke(DispatcherPriority.Input,
new Action(delegate() {
var result = DB.StoreItems(_currentType, ds); // Do Work
if (result)
StatusLabel.Content = "Finished";
else
StatusLabel.Content = "An error has occured";
}));
It should be noted though that its usually considered bad design to lock up an application while something is running.
A better solution would be to run the long-running process on a background thread, and simply disable your application form while it runs. There are many ways of doing this, but my personal preference is using the Task Parallel Library for it's simplicity.
As an example, your code to use a background thread would look something like this:
using System.Threading.Tasks;
...
// Tell user the application is working:
StatusLabel.Content = "Writing to database...";
MyWindow.IsEnabled = False;
// Do actual work after user has been notified:
Task.Factory.StartNew(() => DB.StoreItems(_currentType, ds))
// This runs after background thread is finished executing
.ContinueWith((e) =>
{
var isSuccessful = e.Result;
if (isSuccessful)
StatusLabel.Content = "Finished";
else
StatusLabel.Content = "An error has occured";
MyWindow.Enabled = true;
});
You are trying to solve the problem in the wrong manner. What you should be doing here is run the time-consuming task in a worker thread; this way, your UI will remain responsive and the current question will become moot.
There are several ways you can offload the task to a worker thread; among the most convenient are using the thread pool and asynchronous programming.
It is provably impossible to keep your UI responsive without utilizing additional threads unless your database provides an asynchronous version of the method you're using. If it does provide an asynchronous version of the method then you simply need to use that. (Keep in mind that async does not mean that it's using any other threads. It's entirely possible to create an asynchronous method that never uses additional threads, and that's exactly what's done with most network IO methods.) The specifics of how to go about doing that will depends on the type of DB framework you're using, and how you're using it.
If your DB framework does not provide async methods then the only way to keep the UI responsive is to perform the long running operation(s) in a non-UI thread.
The Approach you are using is not efficient way so I would suggest to go with Async Programing or threading
Async programming:
Visual Studio 2012 introduces a simplified approach, async programming, that leverages asynchronous support in the .NET Framework 4.5 and the Windows Runtime. The compiler does the difficult work that the developer used to do, and your application retains a logical structure that resembles synchronous code. As a result, you get all the advantages of asynchronous programming with a fraction of the effort. Support .Net framework 4.5
It will save your time to implementing System .Threading and very efficient for the task same as your where we have to wait for some operation
http://msdn.microsoft.com/en-ca/library/vstudio/hh191443.aspx
http://go.microsoft.com/fwlink/?LinkID=261549
or
Threading:
The advantage of threading is the ability to create applications that use more than one thread of execution. For example, a process can have a user interface thread that manages interactions with the user and worker threads that perform other tasks while the user interface thread waits for user input.Support .Net fremework 4.0 or Older
http://msdn.microsoft.com/en-us/library/aa645740%28v=vs.71%29.aspx
If you don't want the UI to be responsive I use a busy indicator.
There are prettier cursors - this is an in house application.
using (new WaitCursor())
{
// very long task
Search.ExecuteSearch(enumSrchType.NextPage);
}
public class WaitCursor : IDisposable
{
private Cursor _previousCursor;
public WaitCursor()
{
_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
#region IDisposable Members
public void Dispose()
{
Mouse.OverrideCursor = _previousCursor;
}
#endregion
}

WinForm Application UI Hangs during Long-Running Operation

I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.

Categories

Resources