In WPF both Dispatcher and taskscheduler helps to pass the value from background thread to UI thread. So really what is the difference between them.
For instance in the below code what is the actual Difference between option 1 and option 2
Task<int> tsk = Task<int>.Factory.StartNew(TestMethod);
var threadSchedulder = TaskScheduler.FromCurrentSynchronizationContext();
//Option 1
tsk.ContinueWith((t) =>
{
SetText(tsk.Result);
}, threadSchedulder);
//Option 2
this.Dispatcher.Invoke(() =>
{
SetText(tsk.Result);
});
Both will do almost the same thing and will have its own advantages.
• Dispatcher.BeginInvoke() : Just to Updating something on the UI thread Dispatcher.BeginInvoke is the best option. Typically this is done to update some UI controls with the results of some operation that was executed on a background thread. The Dispatcher.Invoke call will block until this operation completes. We should not execute lengthy operations over here.
Dispatcher.BeginInvoke( () =>{myLabel.Text = "myText"});
• Task.Factory.StartNew() : It is useful when compose multiple tasks together. This makes scheduling work that's dependent on previous tasks far simpler, since you can use Task.WaitAll/Task.WaitAny, as well as continuations.
Related
I am using SynchronizationContext as a means to synchronize to the GUI thread, for WinForms and WPF. Recently I ran into an issue with the old style async callbacks:
private void Button_Click(object sender, RoutedEventArgs e)
{
uiContext = SynchronizationContext.Current;
var cl = new TcpClient();
cl.BeginConnect("127.0.0.1", 22222, ConnectedCallback, null);
}
public void ConnectedCallback(IAsyncResult result)
{
if (SynchronizationContext.Current != uiContext)
uiContext.Post(x => MyUIOperation(), null);
else
MyUIOperation();
}
public void MyUIOperation()
{
Title = "Connected";
}
private SynchronizationContext uiContext;
This will throw an exception, because the SynchronizationContext.Current in the callback function is equal to the captured one, and therefore the UI operation is executed in the worker thread of the callback.
Using this exact same code in WinForms works as I had expected.
For now as a workaround, I am capturing the current ManagedThreadId instead and compare it in the callback. What is correct way to handle this?
Update:
I should add that I am modifying a very old existing class that currently uses the following construct:
if (control.InvokeRequired())
control.BeginInvoke(SomeFunction);
else
SomeFunction();
I am trying to remove the WinForms dependency, without having much impact on the clients of this class. The SomeFunction() is raising events, so if I just call uiContext.Send() or uiContext.Post() , the order of execution is changed since Post() will always queue the call, and Send() will always block.
Also, this is just a very small piece of code to show the root of my issue. In reality the function doing the Post() can be called from the main thread.
This is targeting .NET 4.0
It turned out, in .NET 4.5 the SynchronizationContext is in fact different in the callback function and the if statement would evaluate to true. This was a deliberate change, as discussed here
WPF 4.0 had a performance optimization where it would
frequently reuse the same instance of the
DispatcherSynchronizationContext when preparing the
ExecutionContext for invoking a DispatcherOperation. This
had observable impacts on behavior.
1) Some task-parallel implementations check the reference
equality of the SynchronizationContext to determine if the
completion can be inlined - a significant performance win.
2) But, the ExecutionContext would flow the
SynchronizationContext which could result in the same
instance of the DispatcherSynchronizationContext being the
current SynchronizationContext on two different threads.
The continuations would then be inlined, resulting in code
running on the wrong thread.
Because in my case, the call to MyUIOperation() function would need to
be called immediately if the ConnectedCallback function is called from
the main thread.
That means the call to MyUIOperation() would be a blocking call if the ConnectedCallback is invoked in the UI thread, as opposed to non-blocking if it is invoked from the another thread. This non-determinism could cause other problems down the road.
Just call Send instead. According to this article, the call to Send would just invoke the delegate directly if already in the UI thread.
Also, you could just do Dispatcher.Invoke() instead.
My label text isn't updating properly in my 3.5 WPF MVVM app.
The do work part lasts long enough that you can see the waiting mouse pointer.
All I ever see is "Parsed" in the label, which is Bound to InfoText.
the Dispatcher and do work lines are in a Command's method.
Ideas?
The code
Dispatcher.Invoke((Action<string>)SetInfoText, "Start Parsing");
//do work
Dispatcher.Invoke((Action<string>)SetInfoText, "Parsed");
private void SetInfoText(string text)
{
InfoText = text;
}
private string _infoText;
public string InfoText
{
get
{
return _infoText;
}
set
{
_infoText = value;
OnPropertyChanged("InfoText");
}
}
The only thing I can think of to explain it is that you're doing the work on the UI thread. This would prevent the dispatcher from redrawing until your work is done. The work being passed in Invoke is placed in the event queue, meaning it will be performed when idle.
The proper way to fix it is to do the work on a separate thread. If you're looking for workarounds though, look here.
Reference: MSDN
EDIT:
There are lots of ways to perform the work on another thread. Read up on BackgroundWorker, ThreadPool, Task Parallell Library, Threads. :)
Here's a really simple way to do the work in a background thread:
System.Threading.ThreadPool.QueueUserWorkItem( state =>
{
Dispatcher.Invoke((Action<string>)SetInfoText, "Start Parsing");
System.Threading.Thread.Sleep(5000); // Simulate work
Dispatcher.Invoke((Action<string>)SetInfoText, "Parsed");
});
Application.Current.Dispatcher.BeginInvoke(new Action(() => this.InfoText="Start Parsing"));
this works for me.
nevertheless i would put my long running process in a backgroundworker. so ui thread will not get blocked.
edit: if you do all your work in ui thread you should look at the overload for BeginInvoke - you can pass a DispatcherPriority. may be this helps too
I have an import file method in a WPF app that reads a file and inserts some records in a DB.
This method runs in a BackgroundWorker object.
I have a progress bar being updated inside a Dispatcher.Invoke call. If I run as is, it takes ~1 minute to import 200k records, if I just don't show any progress, it takes just 4 to 5 seconds! And if I use Dispatcher.BeginInvoke with Background priority, it takes the same 4 to 5 seconds, but the progress bar + a counter are being updated and takes ~1 minute. So, obviusly, the UI is the problem here.
And the other problem is that I need to show a progress, so I was thinking if there is any way to use Dispatcher.BeginInvoke but first check if there is anything on the queue and if so, I just skip it, which would behave like: in the 1st second, 1% done, 2 secs later 50% done and in the 4th second 100% done).
Any help on this?
thanks!!!
The problem is that your callbacks are queuing up on the Dispatcher. Each one will cause the screen to repaint, and because they are at Background priority the next one will wait for that repaint to complete before being processed, so you will have to repaint once per callback, which can be slow.
Instead of trying to wait until nothing at all is in the dispatcher queue, just wait until the previous progress callback has been handled before posting a new one. This will ensure you never have more than one active at a time, so they can't queue up.
You can do this by setting a flag when you post the callback and clearing it once it has been processed. For example:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var pending = false;
for (int i = 0; i < 1000000; i++)
{
// Do some work here
// ...
// Only report progress if there is no progress report pending
if (!pending)
{
// Set a flag so we don't post another progress report until
// this one completes, and then post a new progress report
pending = true;
var currentProgress = i;
Dispatcher.BeginInvoke(new Action(() =>
{
// Do something with currentProgress
progressBar.Value = currentProgress;
// Clear the flag so that the BackgroundWorker
// thread will post another progress report
pending = false;
}), DispatcherPriority.Background);
}
}
}
I would simply update a progress counter in the background thread (it only writes to the counter), and have the UI read (only read) the timer every 500 ms or so... There is no reason to update faster than that. Also, because one thread is write only, and one is read only there is no threading issues required. The code becomes massively simpler, cleaner, and more maintainable.
-Chert Pellett
Impossible to say without seeing code, but
I have a progress bar being updated inside a Dispatcher.Invoke call
Why? That's what ReportProgress is for.
If I had to guess (and I do), I'd say you're reporting progress to often. For example, don't report progress after every record, but after batches of 100 or whatever.
I just solved the same case, but using the object returned by BeginInvoke, and I think it’s quite elegant too!
DispatcherOperation uiOperation = null;
while (…)
{
…
if (uiOperation == null || uiOperation.Status == DispatcherOperationStatus.Completed || uiOperation.Status == DispatcherOperationStatus.Aborted)
{
uiOperation = uiElement.Dispatcher.BeginInvoke(…);
}
}
The progress bars become a little choppier (less smooth), but it flies. In my case, the code parses line-by-line from a text file using StreamReader.ReadLine(). Updating the progress bar after reading every line would cause the read operations to complete before the progress bar was even halfway filled. Using the synchronous Dispatcher.Invoke(…) would slow down the entire operation to 100 KiB/s, but the progress bar would accurately track the progress. Using the solution above, my application finished parsing 8,000 KiB in a second with just 3 progress bar updates.
One difference from using BackgroundWorker.ReportProgress(…) is that the progress bar can show finer detail in longer-running operations. BackgroundWorker.ReportProgress(…) is limited to reporting progress in increments of 1% from 0% to 100%. If your progress bar represents more than 100 operations, finer values are desirable. Of course, that could also be achieved by not using the percentProgress argument and passing in a userState to BackgroundWorker.ReportProgress(…) instead.
The classic advice in multithreading programing is to do processor heavy work on a background thread and return the result to the UI thread for minor processing (update a label, etc). What if generating the WPF element itself is the operation which is expensive?
I'm working with a third party library which generates some intense elements, which can take around to 0.75s - 1.5s to render. Generating one isn't too bad, but when I need to create 5 of them to show at once it noticeably locks the UI (including progress spinners). Unfortunately, there isn't any other place to create them because WPF is thread affine.
I've already tried DispatcherPriority.Background but its not enough. What is the recommended way to deal with this problem?
If the objects being created derived from Freezable, then you can actually create them on a different thread than the UI thread - you just have to call Freeze on them while you're on the worker thread, and then you can transfer them over. However, that doesn't help you for items that don't derive from Freezable.
Have you tried creating them one at a time? The following example doesn't do any useful work but it does show how the basic structure for doing a lot of work in little bits:
int count = 100;
Action slow = null;
slow = delegate
{
Thread.Sleep(100);
count -= 1;
if (count > 0)
{
Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);
}
};
Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);
The 'work' here is to sleep for a tenth of a second. (So if you replace that with real work that takes about as long, you'll get the same behaviour.) This does that 100 times, so that's a total of 10 seconds of 'work'. The UI remains reasonably responsive for the whole time - things like dragging the window around become a bit less smooth, but it's perfectly usable. Change both those Background priorities to Normal, and the application locks up.
The key here is that we end up returning after doing each small bit of work having queued up the next bit - we end up calling Dispatcher.BeginInvoke 100 times in all instead of once. That gives the UI a chance to respond to input on a regular basis.
With reference to this programming game I am currently building.
I have a Class Library (dll) that will have a method Run which will be composed of something like such:
public class MyRobot : Robot
{
public void Run(}
{
while (true)
{
Ahead(200); //moves the bot 200pixels
TurnLeft(90); //turns the bot by 90deg
}
}
}
In those methods (inherited from Robot), the system will animate the robot using WPF (using BeginAnimation or the DispatcherTimer).
Now, the problem is that I don't a method to return (ie, move on to the next method) before completing the current one, because that will result in the animations taking place together, and when in an infinite loop (like the one above), that's especially not good.
My question is, what is the best way to prevent a method from returning before completing the animation ?
I currently have a bool in the Robot class (isActionRunning) that be flagged to true when an action starts running and then changes to false in an animation callback (using the Completed event if using BeginAnimation).
At the end of each method (after invoking BeginAnimation) I placed the following loop :
while (isActionRunning)
{
Thread.Sleep(200); //so that the thread sleeps for 200ms and then checks again if the animation is still running
}
This is so that the method won't return before the animation finishes.
But I feel that this is not the right way to do this.
Can anyone guide me to what's best to achieve this ?
Building a signalling device out of locks is craziness; just use the signalling device that already exists in the framework.
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
That is: thread one says "hey thread two, start this animation and signal me on this wait handle when you're done." Thread one then waits on the waithandle. Thread two starts the animation, and in its completion event, signals the waithandle. Thread one then wakes up again and says "hey thread two, start this other animation..."
Here's one option, it will only work if the Robot.Run code is running in a different thread than the UI thread doing the animations.
In the Robot.Ahead method (for example), use Dispatcher.Invoke (not BeginInvoke) to call the method that starts the animation, than add a lock on the robot with an empty block( lock(this) { } ).
In the method that starts the animation call Monitor.Enter(robot) before starting the animation
In the animation complete handler call Monitor.Leave(robot)
The result will be
time robot thread UI thread
| --------------- --------------
| call Invoke --->
| lock robot (Monitor.Enter)
| begin animation
| Invoke returns <--- return
| lock(this) (animation running)
| (wait for lock
| to become available)
|
| Animation complete
| release lock (Monitor.Exit)
| (lock available,
| continue running)
| Release lock (exit lock block)
| Return and start next
| movement
\/
I would do something similar to what you described. I recently worked on something where I called a bunch of asynchronous operations, and I wanted to wait for them all to complete before calling another operation. I created a collection to represent all of the operations currently executing and instead of adding items to the collection directly, I created methods for adding and removing. The remove method had logic that said "lock the collection, remove the key provided, and if empty call the next operation". You could create a similar mechanism like this where a collection scoped at the application or window keeps track of operations being executed. You add a key to the collection and pass this key to your async operation. When the async operation completes, lock the collection and remove the key. Then you can have a loop that blocks your method from returning while the collection contains the key (with optional logic for adding a timeout or any other additional ways where you might want the method to be able to return and not be blocked forever).
This might be overkill, but I have limited experience with this issue myself. For all I know, .Net might even have a canned solution to this problem that works with one or two lines of code.