使用带有 Task.Run() 的异步 lambda 是多余的吗?

问题描述 投票:0回答:3

我刚刚遇到一些代码,例如:

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

(不,我不知道

Foo.StartAsync()
的内部运作原理)。我最初的反应是去掉
async
/
await
并重写为:

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

这是否正确(再次强调,对

Foo.StartAsync()
一无所知)。 This回答它有什么区别 - 使用 Task.Run 运行“异步”操作委托...似乎表明在某些情况下它可能有意义,但它也说“说实话,我还没见过那么多场景……”

c# .net asynchronous task
3个回答
24
投票

通常Task.Run

预期
用法是在非UI线程上执行CPU密集型代码。因此,它很少与
async
委托一起使用,但这是可能的(例如,对于同时具有异步部分和 CPU 绑定部分的代码)。

但是,这就是预期的用途。我认为在你的例子中:

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

原作者更有可能尝试同步阻塞异步代码,并且(ab)使用

Task.Run
避免这种情况下常见的死锁(正如我在博客中所描述的那样)。

本质上,它看起来像我在有关棕地异步代码的文章中描述的“线程池黑客”。

最好的解决方案是不使用

Task.Run
Wait

await Foo.StartAsync();

这将导致

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


10
投票

大部分是的。

像这样使用

Task.Run
主要是由不了解如何执行异步方法的人使用。

但是,还是有区别的。使用

Task.Run
意味着在
ThreadPool
线程上启动异步方法。

当异步方法的同步部分(第一个等待之前的部分)很大并且调用者希望确保该方法不会阻塞时,这可能很有用。

这也可以用于“退出”当前上下文,例如没有

SynchronizationContext
的地方。


0
投票

值得注意的是,您的方法必须标记为

async
才能使用
await
关键字。

所编写的代码似乎是在同步上下文中运行异步代码的解决方法。虽然我不会说你永远不应该这样做,但在几乎所有情况下使用异步方法都是更好的选择。

// use this only when running Tasks in a synchronous method
// use async instead whenever possible
var task = Task.Run(async () => await Foo.StartAsync());
task.Wait();

异步方法,如您的

Foo.StartAsync()
示例,应始终返回
Task
对象。这意味着在异步方法中使用
Task.Run()
创建另一个任务通常是多余的。只需使用
await
关键字即可等待异步方法返回的任务。您应该使用
Task.Run()
的唯一原因是当您执行需要在单独线程上执行的 CPU 密集型工作时。只需使用
await
关键字即可等待异步方法返回的任务。您可以在Microsoft 异步编程指南中阅读更深入的详细信息。

在异步方法中,您的代码可以如此简单:

await Foo.StartAsync();

如果您想在任务运行时执行一些其他工作,您可以将函数分配给变量,然后

await
结果(任务完成)。

例如:

var task = Foo.StartAsync();
// do some other work before waiting for task to finish
Bar();
Baz();
// now wait for the task to finish executing
await task;

对于需要在单独线程上运行的 CPU 密集型工作,您可以使用

Task.Run()
,但是您
await
结果而不是使用线程阻塞
Task.Wait()
:

var task = Task.Run(async () => await Foo.StartAsync());
// do some other work before waiting for task to finish
Bar();
Baz();
// now wait for the task to finish executing
await task;
© www.soinside.com 2019 - 2024. All rights reserved.