views:

169

answers:

2

In my WPF application I need to do an async-operation then I need to update the GUI. And this thing I have to do many times in different moment with different oparations. I know two ways to do this: Dispatcher and BackgroundWorker.

Because when I will chose it will be hard for me to go back, I ask you: what is better? What are the reasons for choosing one rather than the other?

Thank you! Pileggi

+3  A: 

BackgroundWorker is nice if you're doing a single operation, which provides progress notifications and a completion event. However, if you're going to be running the same operation multiple times, or multiple operations, then you'll need more than one BackgroundWorker. In this case, it can get cumbersome.

If you don't need the progress events, then using the ThreadPool and Dispatcher can be simpler - especially if you're going to be doing quite a few different operations.

If C# 4 is an option, however, using the Task Parallel Library is a great option, as well. This lets you use continuation tasks setup using the current SynchronizationContext, which provides a much simpler, cleaner model in many cases. For details, see my blog post on the subject.

Reed Copsey
No, unfortunately I'm working with VB 2008 and fw 3.5 SP1. I'll use ThreadPool and Dispatcher.
pileggi
@Reed Copsey: Thank you very much! now I have a better 'picture' of the problem.
pileggi
+4  A: 

The main difference between the Dispatcher and other threading methods is that the Dispatcher is not actually multi-threaded. The Dispatcher governs the controls, which need a single thread to function properly; the BeginInvoke method of the Dispatcher queues events for later execution (depending on priority etc.), but still on the same thread.

BackgroundWorker on the other hand actually executes the code at the same time it is invoked, in a separate thread. It also is easier to use than true threads because it automatically synchronizes (at least I think I remember this correctly) with the main thread of an application, the one responsible for the controls and message queue (the Dispatcher thread in the case of WPF and Silverlight), so there's no need to use Dispatcher.Invoke (or Control.Invoke in WinForms) when updating controls from the background thread, although that may not be always recommended.

As Reed said, Task Parallel Library is a great alternative option.

Edit: further observations.

As I said above, the Dispatcher isn't really multithreaded; it only gives the illusion of it, because it does run delegates you pass to it at another time. I'd use the Dispatcher only when the code really only deals with the View aspect of an application - i.e. controls, pages, windows, and all that. And of course, its main use is actually triggering actions from other threads to update controls correctly or at the right time (for example, setting focus only after some control has rendered/laid-out itself completely is most easily accomplished using the Dispatcher, because in WPF rendering isn't exactly deterministic).

BackgroundWorker can make multithreaded code a lot simpler than it normally is; it's a simple concept to grasp, and most of all (if it makes sense) you can derive custom workers from it, which can be specialized classes that perform a single task asynchronously, with properties that can function as parameters, progress notification and cancellation etc. I always found BackgroundWorker a huge help (except when I had to derive from it to keep the Culture of the original thread to maintain the localization properly :P)

The most powerful, but also difficult path is to use the lowest level available, System.Threading.Thread; however it's so easy to get things wrong that it's not really recommended. Multithreaded programming is hard, that's a given. However, there's plenty of good information on it if you want to understand all the aspects: this excellent article by our good fellow Jon Skeet immediately jumps to mind (the last page of the article also has a good number of very interesting links).

In .Net 4.0 we have a different option, Task Parallel Library. I haven't worked with it much yet but from what I've seen it's impressive (and PLINQ is simply great). If you have the curiosity and resources to learn it, that's what I'd recommend (it shouldn't take that much to learn after all).

Alex Paven
@Alex Paven: Thank you very much! Why you say "although that may not be always recommended"? When it's not recommended?
pileggi
I think it may decrease performance in some cases, especially in tight loops that also update the UI, so in those cases it might not be recommended. Didn't run into such problems recently, but in one project I noticed async code running quite noticeably slower than the same sync code... Didn't determine for sure if context switching caused by the thread synchronization mechanisms was to blame but I suspect it was.
Alex Paven
@Alex Paven: Thank you! Now I have to choose. From the suggestions of Reed Copsey I have that "using the ThreadPool and Dispatcher can be simpler", from you I have that "it may decrease performance". I have to do nothing into "tight loops", but however the choice is hard! How you choose, if you were me? :-)
pileggi
As always, it depends :) I'll update my answer with some more considerations.
Alex Paven
@Alex Paven:I can tell you this "using the ThreadPool and Dispatcher can be simpler" is true, because the operations are quite different one from each other, and the methods need differnt numbers of parameters. The BGW accept only 1 object param. I don't have the problem that "you'll need more than one BGW. In this case, it can get cumbersome" because I partly lock the application until the async process has been all executed, then I can use always the same BGW. All the async processes are single requests to a web-service. Finally I have fear for your warning about the performance
pileggi
Actually, I think you can derive from the BGW and have some properties (read-only to keep it safe) on the derived object; the constructor can take the parameters, place them in the properties, and the DoWork event can use them. That's effectively encapsulating a threaded action very neatly (of course it isn't fitting for all cases but it's a nice option).
Alex Paven
You don't really need to fear performance - I'm even sorry I brought it up. The cause for poor performance in the project I was talking about was (I'm pretty sure) some COM components which were STA and which I had to use in the multi-threaded code (wasn't nice to keep the UI locked up until the bloody COM code finished it's very slow executions); in the end the multi-threaded code ended up taking around 15 seconds compared to 10 single-threaded, all to have a progress indicator while it was running. But as always, it's always best to make a quick prototype and see how it turns out.
Alex Paven
@Alex Paven: Thank you very much!! I attempt to ask you one last thing: could you, please, give me a little code-sample of your suggestion "you can derive from the BGW and have some properties... and the DoWork event can use them"? Only if it's not a problem.
pileggi
@Alex Paven: I can also write some classes, each of which contains the parameters to pass to the BGW, but it's quite uncomfortable: it's a lot of code to write.
pileggi
http://blogs.msdn.com/b/pigscanfly/archive/2009/08/06/stackoverflow-answer-why-learn-multi-core-programming-2.aspx gives a nice sample. Like I said, it's not always the best way to go, but there's always the simplest option: `bgw.DoWork += (o, e) => MyRealMethod(param);` :)
Alex Paven
Very nice, thank you very much!!!
pileggi