使用`async` lambda与`Task.Run()`冗余?

时间:2015-09-15 16:47:55

标签: c# .net asynchronous task

我刚刚遇到了一些代码:

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

(不,我不知道Foo.StartAsync()的内部运作方式)。我最初的反应是摆脱async / await并重写为:

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

这是否正确(再次,对Foo.StartAsync()一无所知)。对ThisWhat difference does it make - running an 'async' action delegate with a Task.Run ... 回答似乎表明可能存在可能有意义的情况,但它也说“说实话,我没见过那么多场景......”

2 个答案:

答案 0 :(得分:12)

通常Task.Run预期用法是在非UI线程上执行CPU绑定代码。因此,与async委托一起使用它是非常罕见的,但它是可能的(例如,对于同时具有异步和CPU绑定部分的代码)。

然而,这是预期用途。我想在你的例子中:

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

原作者尝试同步阻止异步代码的可能性更大,并且(ab)使用Task.Runavoid deadlocks common in that situation(正如我在博客中描述的那样)。

从本质上讲,它看起来像我在article on brownfield asynchronous code中描述的“线程池黑客”。

最佳解决方案是不使用Task.Run Wait

await Foo.StartAsync();

这会导致async在代码库中增长,这是最好的方法,但现在可能会给开发人员带来无法接受的工作量。这可能是您的前任使用Task.Run(..).Wait()

的原因

答案 1 :(得分:5)

大部分是的。

像这样使用Task.Run主要用于那些不了解如何执行异步方法的人。

然而,存在差异。使用Task.Run表示在ThreadPool线程上启动异步方法。

当异步方法的同步部分(第一次等待之前的部分)很大并且调用者想要确保该方法不会阻塞时,这非常有用。

这也可用于"退出"当前上下文,例如,没有SynchronizationContext