摘要
async、await是在C# 5.0之后引入的一种简化异步操作的方式。使用它们之后,可以使我们的编写异步操作更加方便快捷,维护以及阅读起来更方便。
一个例子
async、await虽然简化了我们编写异步方法。但也很容易让人产生误解。首先看一个例子:
这种加了async、await叫不叫异步呢?答案肯定不是的。我们可以这样叫这种方法:加了async、await标记的同步方法。
再看下面的一个例子
</span><span style="color: #008000;">//</span><span style="color: #008000;"> GetStringAsync returns a Task<string>. That means that when you await the
</span><span style="color: #008000;">//</span><span style="color: #008000;"> task you'll get a string (urlContents). </span>
Task<<span style="color: #0000ff;">string</span>> getStringTask = client.GetStringAsync(<span style="color: #800000;">"</span><span style="color: #800000;">http://msdn.microsoft.com</span><span style="color: #800000;">"</span><span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> You can do work here that doesn't rely on the string from GetStringAsync. </span>
<span style="color: #000000;"> DoIndependentWork();
</span><span style="color: #008000;">//</span><span style="color: #008000;"> The await operator suspends AccessTheWebAsync.
</span><span style="color: #008000;">//</span><span style="color: #008000;"> - AccessTheWebAsync can't continue until getStringTask is complete.
</span><span style="color: #008000;">//</span><span style="color: #008000;"> - Meanwhile,control returns to the caller of AccessTheWebAsync.
</span><span style="color: #008000;">//</span><span style="color: #008000;"> - Control resumes here when getStringTask is complete.
</span><span style="color: #008000;">//</span><span style="color: #008000;"> - The await operator then retrieves the string result from getStringTask. </span>
<span style="color: #0000ff;">string</span> urlContents = <span style="color: #0000ff;">await</span><span style="color: #000000;"> getStringTask;
</span><span style="color: #008000;">//</span><span style="color: #008000;"> The return statement specifies an integer result.
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Any methods that are awaiting AccessTheWebAsync retrieve the length value. </span>
<span style="color: #0000ff;">return</span><span style="color: #000000;"> urlContents.Length;
}
上面的方法GetStringAsync,如果不需要返回值,可以移步进行执行,然后会执行方法DoIndependentWork方法,知道await getStringTask拿到GetStringAsync方法的返回值。
以下特征总结了使上一个示例成为异步方法的原因。
-
方法签名包含
async
修饰符。 -
按照约定,异步方法的名称以“Async”后缀结尾。
-
返回类型为下列类型之一:
-
Void
:如果要编写异步事件处理程序。 -
包含
GetAwaiter
方法的其他任何类型(自 C# 7 起)。
有关详细信息,请参见本主题后面的“返回类型和参数”。
-
方法通常包含至少一个 await 表达式,该表达式标记一个点,在该点上,直到等待的异步操作完成方法才能继续。 同时,将方法挂起,并且控件返回到方法的调用方。 本主题的下一节将解释悬挂点发生的情况。
在异步方法中,可使用提供的关键字和类型来指示需要完成的操作,且编译器会完成其余操作,其中包括持续跟踪控件以挂起方法返回等待点时发生的情况。 一些常规流程(例如,循环和异常处理)在传统异步代码中处理起来可能很困难。 在异步方法中,元素的编写频率与同步解决方案相同且此问题得到解决。
上面的方法执行过程
关系图中的数值对应于以下步骤。
-
事件处理程序调用并等待
AccessTheWebAsync
异步方法。 -
AccessTheWebAsync
可创建 实例并调用 异步方法以下载网站内容作为字符串。 -
GetStringAsync
中发生了某种情况,该情况挂起了它的进程。 可能必须等待网站下载或一些其他阻止活动。 为避免阻止资源,GetStringAsync
会将控制权出让给其调用方AccessTheWebAsync
。GetStringAsync
返回 ,其中TResult
为字符串,并且AccessTheWebAsync
将任务分配给getStringTask
变量。 该任务表示调用GetStringAsync
的正在进行的进程,其中承诺当工作完成时产生实际字符串值。 -
由于尚未等待
getStringTask
,因此,AccessTheWebAsync
可以继续执行不依赖于GetStringAsync
得出的最终结果的其他工作。 该任务由对同步方法DoIndependentWork
的调用表示。 -
AccessTheWebAsync
已用完工作,可以不受getStringTask
的结果影响。 接下来,AccessTheWebAsync
需要计算并返回该下载字符串的长度,但该方法仅在具有字符串时才能计算该值。因此,
AccessTheWebAsync
使用一个 await 运算符来挂起其进度,并把控制权交给调用AccessTheWebAsync
的方法。AccessTheWebAsync
将Task
返回给调用方。 该任务表示对产生下载字符串长度的整数结果的一个承诺。
总结
简单一句话,并不是所有的加了async和await关键字的方法就是异步方法。可以这样理解 await 的位置决定了到底是不是异步方法,如果直接await xxxAsync那么是挂起当前方法直到拿到返回值才会执行下面的逻辑,这样就是一种同步方法了。异步是类似这样的 代码块:
<span style="color: #0000ff;">await
<span style="color: #000000;"> t; <span style="color: #008000;">//<span style="color: #008000;">结束参考文章