I have 2 kinds of C# WPF app projects:
- based on .NET 4.0 that I cannot migrate to .NET 4.5
- based on .NET 4.0 that I can migrate to .NET 4.5
All of them should spawn 2-10 long-running (days) processes which can be cancelled and re-launched by users.
I am interested to follow the best design practices. First of all, now, I am interested to disambiguate about BackgroundWorker
usage though, I hope, my question should be valid about other asynchronous patterns.
I see (contradicting) concurrent points of view about
asynchronous patterns:
A) .NET 4.5 made them obsolete
- named as such in the book By Joseph Albahari, Ben Albahari "C# 5.0 in a Nutshell: The Definitive Reference" in sub-chapter "Obsolete Patterns" while its previous edition ""C# 4.0 in a Nutshell: The Definitive Reference" did not
- MSDN article "Asynchronous Programming with Async and Await (C# and Visual Basic)" tells:
"The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool"
- B) They (or, at least,
BackgroundWorker
) are not obsolete in .NET 4.5
I am still in doubt:
- Are those patterns (first of all, BGW) obsolete in .NET 4.5 ?
If they are obsolete in .NET 4.5 why aren't they obsolete in .NET 4.0?
2A) Do I understand incorrectly that .NET 4.5 new features are still "easy" implementable/reproducible in .NET 4.0?
My question was:
i.e. a doubt, asking for confirmation or negation that if something is obsolete in .NET 4.5, then I do not see why and how it can be different in .NET 4.0, i.e. with Task Parallel Library (without
async/await
engagement and .NET 4.5 support exclusively)And I am quite happy to find Nick Polyak's answers in his codeproject article "Task Parallel Library and async-await Functionality - Patterns of Usage in Easy Samples" stated:
BackgroundWorker
is all but obsolete now, but you still might come across some instances when it is necessary to use the EAP pattern. In such cases, it will be nice to produce Task objects out of the EAP functionality so that you'll be able to schedule them to run in parallel or wait for a number of previous Tasks to finish etc. In this section we show how to achieve it"BackgroundWorker
functionality largerly obsolete - you can achieve whatever you need using a Task instead of a BackgroundWorker. Still there might be some reason you want to useBackgroundWorker
functionality on the team - whether because your legacy code uses it or because most of your team members or your boss love it and understand it better than the newer Task functionality"still being open to see any different argumented points of view
I generally recommend
Task
and/orawait
if using .NET 4.5. ButTask
& BGW have 2 distinctly different scenarios. Task is good for general short asynchronous tasks that could be chained to a continuation and await is good at tasks implicitly marshalling back to the UI thread. BGW is good for a single long operation that shouldn't affect the responsiveness of your UI. You can drag-drop a BGW onto design surface and double-click to create event handlers. You don't have to deal withLongRunning
orConfigureAwait
if you don't want to marshal to another thread. Many find BGW progress easier thanIProgress<T>
.Here's some examples of using both in a "lengthy operation" scenario:
Since the question specifically mentions .NET 4.0, the following is simple code that uses a
Task
to do a lengthy operation while providing progress to a UI:Similar code with
BackgroundWorker
might be:Now, if you were using .NET 4.5 you could use
Progress<T>
instead of theBeginInvoke
call withTask
. And since in 4.5, usingawait
would likely be more readable:Using
Progress<T>
means the code is not coupled to a specific UI framework (i.e. the call toBeginInvoke
) in much the same way thatBackgroundWorker
facilitates decoupling from a specific UI framework. If you don't care, then you don't need to introduce the added complexity of usingProgress<T>
As to
LongRunning
, as Stephen Toub says: "You'd typically only use LongRunning if you found through performance testing that not using it was causing long delays in the processing of other work" so, if you find you need to use it, then you use it--there's the added analysis or just the "complexity" of always adding theLongRunning
parameter. Not using LongRunning means the thread pool thread used for the long running operation won't be usable for other, more transient, tasks and could force the thread pool to delay starting one of these transient tasks while it starts up another thread (at least a second).There's no attributes in the framework that specifically say that BGW (or EAP, or APM) are deprecated. So, it's up to you to decide where and when any of these things are "obsolete". BGW in particular always had a very specific usage scenario that still applies to it. You have fairly decent alternatives in .NET 4.0 and 4.5; but I don't really think BGW is "obsolete".
I'm not saying always use
BackgroundWorker
, I'm just saying think before you automatically deprecate BackgroundWorker, in some cases it might be a better choice.I consider these patterns (APM, EAP, and BGW in particular) obsolete in .NET 4.5. The combination of
async
withTask.Run
is superior to BGW in every way. In fact, I just started a series on my blog where I will compare BGW toTask.Run
and show how it's more cumbersome in every situation; there are some situations where it's just slightly more cumbersome, but there are other situations where it's much more cumbersome.Now, whether they're obsolete in .NET 4.0 is another question entirely. From your other posts, you're talking about developing for .NET 4.0 with VS2010, so the backport
Microsoft.Bcl.Async
isn't an option. In that case, neither APM nor EAP can be considered obsolete IMO. On this platform, you can considerTask.Factory.StartNew
as an alternative to BGW but BGW does have some advantages when it comes to progress reporting and automatic thread marshaling of its progress and completion events.Update: I did recently update an old blog post of mine where I discuss various implementations of background operations. In that post, when I talk about "Tasks (Async Methods)", I mean using
Task
with all the .NET 4.5async
support,Task.Run
, etc. The "Tasks (Task Parallel Library)" section is evaluatingTask
as it existed in .NET 4.0.