is using an an `async` lambda with `Task.Run()` redundant?

26,945

Solution 1

Normally, the intended usage for Task.Run is to execute CPU-bound code on a non-UI thread. As such, it would be quite rare for it to be used with an async delegate, but it is possible (e.g., for code that has both asynchronous and CPU-bound portions).

However, that's the intended usage. I think in your example:

var task = Task.Run(async () => { await Foo.StartAsync(); });
task.Wait();

It's far more likely that the original author is attempting to synchronously block on asynchronous code, and is (ab)using Task.Run to avoid deadlocks common in that situation (as I describe on my blog).

In essence, it looks like the "thread pool hack" that I describe in my article on brownfield asynchronous code.

The best solution is to not use Task.Run or Wait:

await Foo.StartAsync();

This will cause async to grow through your code base, which is the best approach, but may cause an unacceptable amount of work for your developers right now. This is presumably why your predecessor used Task.Run(..).Wait().

Solution 2

Mostly yes.

Using Task.Run like this is mostly used by people who don't understand how to execute an async method.

However, there is a difference. Using Task.Run means starting the async method on a ThreadPool thread.

This can be useful when the async method's synchronous part (the part before the first await) is substantial and the caller wants to make sure that method isn't blocking.

This can also be used to "get out of" the current context, for example where there isn't a SynchronizationContext.

Share:
26,945
Rajee
Author by

Rajee

(Your about me is currently blank.)

Updated on July 09, 2022

Comments

  • Rajee
    Rajee almost 2 years

    I just came across some code like:

    var task = Task.Run(async () => { await Foo.StartAsync(); });
    task.Wait();
    

    (No, I don't know the inner-workings of Foo.StartAsync()). My initial reaction would be get rid of async/await and rewrite as:

    var task = Foo.StartAsync();
    task.Wait();
    

    Would that be correct, or not (again, knowing nothing at all about Foo.StartAsync()). This answer to What difference does it make - running an 'async' action delegate with a Task.Run ... seems to indicate there may be cases when it might make sense, but it also says "To tell the truth, I haven't seen that many scenarios ..."