关系图中的数值对应于以下步骤。
-
事件处理程序调用并等待
AccessTheWebAsync
异步方法。 -
AccessTheWebAsync
可创建HttpClient
实例并调用GetStringAsync
异步方法以下载网站内容作为字符串。 -
GetStringAsync
中发生了某种情况,该情况挂起了它的进程。 可能必须等待网站下载或一些其他阻止活动。
为避免阻塞资源,GetStringAsync
会将控制权出让给其调用方AccessTheWebAsync
。GetStringAsync
返回Task<TResult>
,其中TResult
为字符串,并且AccessTheWebAsync
将任务分配给getStringTask
变量。 该任务表示调用GetStringAsync
的正在进行的进程,其中承诺当工作完成时产生实际字符串值。 -
由于尚未等待
getStringTask
,因此,AccessTheWebAsync
可以继续执行不依赖于GetStringAsync
得出的最终结果的其他工作。 该任务由对同步方法DoIndependentWork
的调用表示。 -
DoIndependentWork
是完成其工作并返回其调用方的同步方法。 -
AccessTheWebAsync
已运行完可以不受getStringTask
结果影响的工作任务。
接下来,AccessTheWebAsync
需要计算并返回该下载字符串的长度,但该方法仅在具有字符串时才能计算该值。因此,
AccessTheWebAsync
使用一个await
运算符来挂起其进度,并把控制权交给调用AccessTheWebAsync
的方法。AccessTheWebAsync
将Task<int>
返回给调用方。 该任务表示对产生下载字符串长度的整数结果的一个承诺。如果
GetStringAsync
(因此getStringTask
)在AccessTheWebAsync
等待前完成,则控制会保留在AccessTheWebAsync
中。 如果异步调用过程 (getStringTask
) 已完成,并且AccessTheWebSync
不必等待最终结果,则挂起然后返回到AccessTheWebAsync
将造成成本浪费。在调用方内部(此示例中的事件处理程序),处理模式将继续。 在等待结果前,调用方可以开展不依赖于
AccessTheWebAsync
结果的其他工作,否则就需等待片刻。 事件处理程序等待AccessTheWebAsync
,而AccessTheWebAsync
等待GetStringAsync
。 -
GetStringAsync
完成并生成一个字符串结果。 字符串结果不是通过按你预期的方式调用GetStringAsync
所返回的。(记住,该方法已返回步骤 3 中的一个任务)。相反,字符串结果存储在表示getStringTask
方法完成的任务中。await
运算符从getStringTask
中检索结果。 赋值语句将检索到的结果赋给urlContents
。 -
当
AccessTheWebAsync
具有字符串结果时,该方法可以计算字符串长度。 然后,AccessTheWebAsync
工作也将完成,并且等待事件处理程序可继续使用。 在此主题结尾处的完整示例中,可确认事件处理程序检索并打印长度结果的值。
如果你不熟悉异步编程,请花 1 分钟时间考虑同步行为和异步行为之间的差异。 当其工作完成时(第 5 步)会返回一个同步方法,但当其工作挂起时(第 3 步和第 6 步),异步方法会返回一个任务值。
在异步方法最终完成其工作时,任务会标记为已完成,而结果(如果有)将存储在任务中。