Reputation: 12264
From https://msdn.microsoft.com/en-us/library/mt674882.aspx#Threads:
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.
It seems to me that a chain of async
functions must eventually end in waiting for something to happen that is outside of your program's control. Some Internet download or user input or something.
What about situations when your program must perform some lengthy calculation? It would have to be in a method that doesn't itself use await
, because there's nothing to wait for when it's doing all the work itself. If await
is not used then control wouldn't return back to the calling function, correct? If that's the case then surely it's not even asynchronous at all.
It seems BackgroundWorker
is well-suited for lengthy calculations: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx#Examples
Is there any way to use async
/await
for that purpose?
Upvotes: 2
Views: 1997
Reputation: 5857
The key is here:
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.
For a CPU-bound work (or IO-bound, it does not matter), Task.Run
will run your code in a separate thread from thread pool, so the current code can await
it, because it is running on a different thread. From the perspective of the second thread, the work is synchronous, but from the perspective of the first thread, the work is asynchronous.
The second thing is the coordination context. I have not used BackgroundWorker
, but from my understanding of the text, it will need you to manually check if the work is done, and then retrieve the results, or maybe propagate exceptions, and so on. In async/await
approach, all of this is covered for you.
All in all, it seems that async/await
approach is a more friendly readable way of doing things compared to BackgroundWorker
way.
Edit:
You can't use await
on non-awaitable
methods. A CPU-bound task can never be truly asynchronous, because something needs to be calculated, and a thread is needed for that. Either the current thread will do the calculation (blocking), or will give it to another background thread, so the current thread is not blocking and asynchronous.
If you are familiar with Node.js, you will notice that it is quite tricky to handle CPU-bound tasks, and often times you will need to refactor your code.
However, as user, your current thread is asynchronous regardless of whether the method you are awaiting is truly asynchronous or using another thread.
Upvotes: 2
Reputation: 456477
It seems to me that a chain of async functions must eventually end in waiting for something to happen that is outside of your program's control.
Yes; pure async
code is generally used with I/O or other "events" (e.g., timers, notifications, or - less commonly - user input).
What about situations when your program must perform some lengthy calculation?
This is not the primary use case of async
. However, it is a great use case for parallel computation (Parallel
/ PLINQ), or if the work is smaller, the thread pool (Task.Run
).
If await is not used then control wouldn't return back to the calling function, correct? If that's the case then surely it's not even asynchronous at all.
That's correct; an async
method without await
would in fact run synchronously. And in fact, if you type that into Visual Studio, the compiler will give you a warning that actually says "this method will run synchronously". Because most of the time, that's a mistake.
If you want to run CPU-bound code on a thread pool thread, then use Task.Run
. You can (and usually should) await
the task returned by Task.Run
, which allows the caller to treat the thread pool work as though it were asynchronous (even though it's really just running synchronously on a background thread):
await Task.Run(() => ...);
If you want the full power of parallel processing, you can just wrap that up inside the Task.Run
:
await Task.Run(() => Parallel.ForEach(...));
It seems BackgroundWorker is well-suited for lengthy calculations
Not really. Retrieving results is a bit awkward, since it's easy to miss errors, and the results aren't type-safe. Also, coordinating multiple BGWs quickly becomes difficult. I have a blog series that shows how BackgroundWorker
should essentially be considered obsoleted by Task.Run
.
Upvotes: 1