异步等待和Task.Run问题

时间:2018-11-02 13:25:57

标签: c# multithreading task

我需要知道这些记录中是否有差异,如果有,它们是什么? 对我来说很困难:

1) Task.Run(async () => { await CheckVerification(); });
2) Task.Run(() => CheckVerification());
3) await Task.Run(async () => { await CheckVerification(); });

2 个答案:

答案 0 :(得分:0)

如果我们忘记Task.Run一秒钟,也许更容易理解它们之间的区别。第一点和第二点之间的区别基本上与等待或仅从Task返回方法返回内部任务相同:

// 1)
public async Task WithAwait() => await SomeOtherTaskReturningMethod();

// 2)
public Task WithoutAwait() => return SomeOtherTaskReturningMethod();

第一个创建另一个任务,该任务包装内部任务,这是一个很小的开销,但是在其他方面,这两种方法在功能上几乎相同。一个小的区别是,当SomeOtherTaskReturningMethod引发异常时,内部任务的AggregatedException将被解包,并且(第一个)内部异常将被进一步引发。当然,事情仍然取决于外部任务发生了什么。在您的第3点上,它也在等待中,因此您将从外部任务(如果有)中获得未包装的异常,而第1和第2个示例只是开火而忘却。

现在,让我们再次考虑Task.Run。主要问题是,当您也可以简单地调用Task并获得相同结果时,为什么此方法具有重载,它们接受Task(实际上是await CheckVerification();个返回的回调)? (我知道这不是问题的一部分,但也许值得澄清)

因此存在Task.Run重载的原因是,Task返回方法本身不一定在另一个线程上执行(我建议this reading)。例如,它可以仅通过网络套接字发送一条消息并返回一个Task,当收到特定答案时,将完成此操作。这使操作异步,但仍不是多线程的。

如果您有这样的任务,并且希望将其强制在另一个线程上执行,那么您可以通过Task.Run执行该任务,该命令将使用默认调度程序,并最终在池线程上执行您的任务。

值得一提的是,这是一种非常罕见的情况。在大多数情况下,您应该依靠Task返回方法的内部实现。

TL; DR:

所以我认为真正的问题是是否

await CheckVerification();

await Task.Run(() => CheckVerification());

是更好的解决方案(或者其中一种不带await的解雇模式)。在大多数情况下,我会投票赞成第一个选项,但是如果您确实有信心必须将CheckVerification返回的任务分配给一个池线程(无论是否在内部执行),那么第二个选项也可以有道理。

答案 1 :(得分:-1)

1)开始任务。该任务将等待内部的方法,但会异步进行,因此您的UI或调用线程将不会阻塞。

2)启动一个任务,再启动另一个任务。一切都异步运行,什么都没有等待,完全着火而忘记了。

3)将启动一个任务,该任务启动一个方法并等待它,返回执行上下文,让调用线程以其等待状态释放执行上下文,让调用此方法的方法继续执行,直到等待它为止方法。