I had quite a few comments on my last post asking for more explicit examples of Correct vs. Incorrect
First, let’s consider the “beginner’s error”. This is where the user misuses
Task.Run because they want to make their code “asynchronous” but aren’t sure how to do it.
This kind of user starts off with existing code, which usually does some kind of synchronous work (often database access or a web request).
They’ve read a bit about how
async helps in those areas, and decide to give it a spin. “Let’s see if I can figure out this
async thing. I’ll just add an
async and see what happens. Oh, I have to change the return type to
“Now the compiler is complaining that I’m not using
await. OK, so what can I await? [Google-Fu] Ah,
Task.Run looks promising!”
“Hey, it worked! My UI thread is no longer blocked! Yay for
Unfortunately, this is a misuse of
Task.Run. The problem is that it’s not truly asynchronous. It’s still executing blocking work, blocking a thread pool thread the whole time the operation is in progress.
The proper approach is to change the blocking call to an asynchronous call first and then allow
async to grow from there. So, starting from the same point, we first change the blocking call to an asynchronous call. In the real world, this would be like replacing
HttpClient or converting your Entity Framework queries to be asynchronous. In this example, I’m replacing
Now we’re getting a compiler error, and we need to make the method
And now we end up with a more correct implementation.
Note that this was an example of using
Task.Run for the wrong thing. To reiterate a sentence from my last post, use
Task.Run to call CPU-bound methods (from GUI threads). Do not use it just to “provide something awaitable for my async method to use”.