45

.Net 4.5 中的异步任务(Async/Await)如何工作?

一些示例代码:

private async Task<bool> TestFunction()
{
  var x = await DoesSomethingExists();
  var y = await DoesSomethingElseExists();
  return y;
}

第二个await语句是立即执行还是在第一个await返回后执行?

4

3 回答 3

51

await暂停方法直到操作完成。所以第二个await将在第一个await返回后执行。

有关更多信息,请参阅我的async/await介绍官方常见问题解答

于 2012-10-26T11:53:55.683 回答
15

它在第一个 await 返回后执行。如果这件事让您感到困惑,请尝试使用断点 - 新的异步模式完全支持它们。

想象一下它看起来像这样:

var x = await GetSomeObjectInstance();
var y = await GetSomeObjectInstance2(x);

某处可能会发生 NullReferenceException,因此第一个 await必须先返回。否则,x将为空/未定义或其他。

于 2012-10-26T07:02:48.050 回答
13

方法调用仍将像“常规”、非等待的方法调用一样按顺序发生。await 的目的是它会将当前线程返回到线程池,而等待的操作运行并执行任何操作。

这在高性能环境中特别有用,例如 Web 服务器,其中给定请求在整个线程池中的给定线程上处理。如果我们不等待,那么在 db / service 调用完成时,处理请求(及其所有资源)的给定线程将保持“正在使用”。这可能需要几秒钟或更长时间,尤其是对于外部服务调用。

现在在低流量网站中,这不是什么大问题,但在高流量网站中,所有这些请求线程的成本只是闲置,无所事事,处于“使用中”状态,等待其他进程,如那些 db /service 调用返回可能是一种资源负担。

我们最好将线程释放回工作池,以允许它为其他请求做其他有用的工作。

一旦 db / service 调用完成,我们就可以中断线程池并请求一个线程从中断的地方继续处理该请求。此时请求的状态被重新加载并且方法调用继续。

因此,在使用 await 时,在每个请求的基础上,从用户的角度来看,请求仍将花费相同的时间……加上一点点更多的切换开销。

但总的来说,在所有用户的所有请求中,对于所有用户来说,事情似乎更具性能,因为 Web 服务器(在这种情况下)运行效率更高,资源利用率更高。即它要么不必排队等待空闲线程处理请求的请求,因为 await 正在返回它们,要么我们不必购买更多硬件,因为我们使用相同数量的硬件,更有效地获得更高吞吐量。

不过,这有一个转换成本,因此尽管您在默认模板和许多文档中看到了什么,但您不应该只是盲目地为每个调用使用 await。它只是一个工具,就像所有工具一样,它也有它的位置。如果切换成本不低于同步完成调用的成本,那么您不应该使用 await。

于 2014-06-04T03:10:01.180 回答