在等待任务返回之前会发生什么?

时间:2013-07-06 14:45:09

标签: c# asynchronous async-await

我正在尝试使用新的async和await关键字。我生成了以下异步函数:

private async static Task<string> GetStringAsync(string pageAddress)
{
    HttpClient client = new HttpClient();
    return client.GetStringAsync(pageAddress);
}

我知道我正在返回Task<String>并且可以等待另一种方法的结果。这种方法很好。我的问题是当我用以下内容替换上面函数的第二行时会发生什么(在引擎盖下)(请注意引入 await 关键字):

return await client.GetStringAsync(pageAddress);

该功能的行为方式完全相同!请记住,该函数返回Task<string>而不是string。此处的await关键字是否已退化?编译器是否只是从我的代码中删除它?

3 个答案:

答案 0 :(得分:7)

这个问题的答案太大了,不能在这里发布,因为你可能目前的理解水平。你应该做的是先阅读我的MSDN文章,然后阅读Mads的MSDN文章;它们是该功能的初学者入门,Mads描述了它是如何实现的。你可以在这里找到链接:

http://blogs.msdn.com/b/ericlippert/archive/2011/10/03/async-articles.aspx

然后,如果您对该功能的基础理论感兴趣,您应该首先阅读我关于延续传递风格的所有文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+style/

从底部开始。一旦理解了 continuation 的概念,您就可以阅读我关于如何设计异步功能的一系列文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/async/

答案 1 :(得分:6)

正如Eric Lippert指出的那样,第一个版本将无法编译;您必须删除async关键字,否则会出现类型错误。

这是关于asyncawait关键字如何与返回类型一起使用的有用心理模型:

  • T方法返回的任何值async都会“包装”到Task<T>
  • await关键字(您可以将其视为运算符),当应用于Task<T>时,将“解包”它,从而产生类型为T的值。< / LI>

现在,这是一种极端的简化;实际发生的事情更复杂。例如,此简化会跳过await如何使用当前SynchronizationContext:在第二个示例中,该方法将尝试在await完成后返回到原始上下文,因此您将观察如果上下文繁忙,则会有不同的行为。

但在大多数情况下,这两个例子几乎相同。由于async状态机并且在上下文中恢复,第二个效率较低。

我有async/await intro您可能会觉得有帮助;在该帖子中,我尝试以一种非复杂但实际上不正确的方式解释async。 :)

答案 2 :(得分:2)

Eric显然是这里的专家,他的建议很合理,但要回答你的具体问题:

在第一个版本中,该方法的async关键字无关紧要,而您的GetStringAsync方法返回的Task<string>等同于client.GetStringAsync所返回的async

在第二个版本中,该方法的await关键字是必需的,因为您在方法中使用await并且Task<string>关键字创建并返回单独的client.GetStringAsync一旦等待await完成,就等待完成。发生这种情况时,client.GetStringAsync将计算为GetStringAsync异步获取的字符串,该字符串将作为异步方法的结果返回。

所以对于{{1}}的来电者来说,它们在功能上是相同的,但第一个版本更清晰。