Task.Run vs BackgroundWorker: Conclusion
• CommentsIn this series on Task.Run vs BackgroundWorker, we’ve looked at the most common aspects of running background tasks. As a recap, here’s the full list of posts in chronological order:
- Introduction - we’re only contrasting
Task.Run
withBackgroundWorker
for situations thatBackgroundWorker
was designed for. - Round 1: Basics - how to run code on a background thread and receive a completion notification marshaled back to the UI thread. The
Task.Run
code is shorter and simpler with less “ceremony code”. - Round 2: Errors - how to handle exceptions from the background thread code. The
Task.Run
code uses the more natural and less error-pronetry/catch
blocks, and has less error-prone exception propagation. - Round 3: Results - how to retrieve a result value from the background thread. The
Task.Run
code uses the more naturalreturn
statement and the result value is strongly-typed. - Round 4: Cancellation - how to cancel the background thread. The
Task.Run
code uses the common cancellation framework, which is simpler, less error-prone, and interoperates more cleanly with other cancellation-aware APIs. - Round 5: Progress Reports - how to support progress updates from the background thread. The
Task.Run
code uses a strongly-typed progress report type.
What I am not planning to cover in this series are more complex situations, which is actually where Task.Run
really outperforms BackgroundWorker
. For example, nesting one background operation within another is easier with Task.Run
. Also, anything like waiting for two separate background operations to complete before doing something else is much easier with Task.Run
. Pretty much any time you have to coordinate background operations, Task.Run
code is going to be much simpler!
I hope that this series is sufficient to convince you that BackgroundWorker
is a type that should not be used in new code. Everything it can do, Task.Run
can do better; and Task.Run
can do a lot of things that BackgroundWorker
can’t!
I’ll leave you with a “combined” example. The code below starts a cancelable background operation that reports progress, and will either throw an exception or return a value. These are all the basic operations of BackgroundWorker
. One of these uses BackgroundWorker
and the other uses Task.Run
. Don’t just look at the length of the code; consider all the little nuances of how it works (type safety, how easily the API can be misused, etc). Then ask yourself: which code would I rather maintain?