15.5.5 【Task实现细节】围绕 await 表达式的控制
任何 await 表达式均表示执行路径的一个分支。首先,被等待的异步操作得到一个awaiter,
然后检查其 IsCompleted 属性。若返回 true ,即可立即获得结果并继续。否则,需进行以下处理。
存储awaiter,以供后面使用。
更新状态,以表示从哪里继续。
为awaiter附加后续操作。
从 MoveNext() 返回,确保不会执行任何 finally 块。
然后,在调用后续操作时,需跳转到正确的地方,获取awaiter并重置状态,然后继续。
例如,代码清单15-11中的第一个 await 表达式即:
await Task.Delay(unicode);
所生成的代码如下所示:
TaskAwaiter localTaskAwaiter = Task.Delay(unicode).GetAwaiter();
if (localTaskAwaiter.IsCompleted)
{
goto FirstAwaitCompletion;
}
state = ;
taskAwaiter = localTaskAwaiter;
builder.AwaitUnsafeOnCompleted(ref localTaskAwaiter, ref this);
doFinallyBodies = false;
return;
FirstAwaitRealContinuation:
localTaskAwaiter = taskAwaiter;
taskAwaiter = default(TaskAwaiter);
state = -;
FirstAwaitCompletion:
localTaskAwaiter.GetResult();
localTaskAwaiter = default(TaskAwaiter);
如果等待的操作有返回值(如使用 HttpClient 分配 await client.GetStringAsync(...) 的结果),那么上述代码末尾处的 GetResult() 调用将得到该值。
AwaitUnsafeOnCompleted 方法将后续操作附加给awaiter, MoveNext() 方法开头的 switch 语句可确保再次执行 MoveNext() 时,将控制传递给 DemoAwaitContinuation 。
说明 AwaitOnCompleted 和 AwaitUnsafeOnCompleted 在此前展示的一组接口中, IAwaiter<T> 扩展了 INotifyCompletion 及其 OnCompleted 方法,此外还扩展了 ICriticalNotifyCompletion 接口及其 UnsafeOnCompleted 方法。状态机为实现 ICriticalNotifyCompletion 的 awaiter 调用 builder.AwaitUnsafeOnCompleted ,或 为只实现 INotifyCompletion 的 awaiter 调用 builder.AwaitOnCompleted 。15.6.4节 在讨论可等待模式如何与上下文交互时,会介绍这两个调用间的区别。
注意,编译器为awaiter消除了局部变量和实例变量,这样就可以适时进行垃圾回收。 如果单个的 await 表达式也可以像这样找到块,则生成代码在反编译模式下不会太难以阅 读。由于CLR的限制,可能会存在较多的 goto 语句(及相应的标签),但在我看来, await 模式 才是最难理解的。 还有一个概念必须加以解释,那就是状态机中神秘的 stack 变量。
15.5.5 【Task实现细节】围绕 await 表达式的控制的更多相关文章
- 15.5.3 【Task实现细节】状态机的结构
状态机的整体结构非常简单.它总是使用显式接口实现,以实现.NET 4.5引入的 IAsync StateMachine 接口,并且只包含该接口声明的两个方法,即 MoveNext 和 SetState ...
- 15.5.6 【Task实现细节】跟踪栈
谈到栈帧(stack frame)时,可能会想到在方法中声明的局部变量.当然,可能还会注意到 一些隐藏的局部变量,如 foreach 循环中的迭代器.但栈上的内容不止这些,至少逻辑上是这样 . 很多 ...
- 15.5.2 【Task实现细节】骨架方法的结构
尽管骨架方法中的代码非常简单,但它暗示了状态机的职责.代码清单15-11生成的骨架方 法如下所示: [DebuggerStepThrough] [AsyncStateMachine(typeof(De ...
- 15.5.1【Task实现细节】 生成的代码
还在吗?我们开始吧.由于深入讲解需上百页的篇幅,因此这里我不会讲得太深.但我会提 供足够的背景知识,以有助于你对整个结构的理解.之后可通过阅读我近些年来撰写的博客文章, 来了解更加错综复杂的细节,或简 ...
- 15.5.4 【Task实现细节】一个入口搞定一切
如果你反编译过异步方法(我非常希望你会这么做),会看到状态机中的 MoveNext() 方法 非常长,变化非常快,像是一个计算有多少 await 表达式的函数.它包含原始方法中的所有逻辑, 和处理所有 ...
- 理解Task和和async await
本文将详解C#类当中的Task,以及异步函数async await和Task的关系 一.Task的前世今生 1.Thread 一开始我们需要创建线程的时候一般是通过Thread创建线程,一般常用创建线 ...
- 【多线程】 Task ,async ,await
[多线程]Task ,async ,await 一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 ...
- C#的Task、async、await关键字
Task,一个类,可以执行一个方法,构造函数需要传一个Action类型的委托,Action类型的委托是可以拥有多个参数,没有返回值的. Task<T> Task的泛型,构造函数传入一个Fu ...
- .net 关于Task.Run 和 Async await的执行顺序
一直捋不清楚用Task.Run异步的执行关系,网上找的些说明写得也有点复杂,所以自己做实验测一下. 直接上代码 这个是加await private static void TestFun() { Co ...
随机推荐
- N天学习一个Linux命令之top
用途 查看机器负载以及进程资源占用情况,linux系统性能分析工具 用法 top -hv | -abcHimMsS -d delay -n iterations -p pid [, pid ...] ...
- CF #321 (Div. 2) E
用线段树维护哈希,类似于进位制的一个哈希 a[i]*p^i+a[i-1]*p^i-1... 然后,线段树存在某区间的哈希的值,对于更新,则只需提前计算出整段的哈希值即可. 判断是否相等,由于相隔为d, ...
- rsync + inotify 打造多server间文件实时同步
在上篇文章ssh无password登陆server的基础之上.能够利用rsync + Inotify 在多server间实现文件自己主动同步. 例如以下測试机基于三台server做的.内网IP分别例如 ...
- Swift基本常识点
import Foundation // 单行注释 // 多行注释(支持嵌套,OC是不支持的) // 常量let,初始化之后就不可改变. // 常量的具体类型可以自动识别,等号后面是什么类型,它就是什 ...
- 使用Linq 查询数据 构建对象 select new{}
linq 查询数据 /// <summary> /// 汽车品牌及车型 /// </summary> /// <returns></returns> p ...
- Web实际应用中的编码问题
一. JSP页面有关编码的介绍 ---->>假设不做不论什么设置,页面默认ISO-8859-1编码(Western European). ---->><%@ page c ...
- 在ubuntu中安装photoshop cs6
对于很多专业的PS高手来说,真心难以找到顺手的且可以完美替代PS的软件,所以我们这里的解决办法就是用wine来安装. 虽然网上有很多的wine安装ps的方法,但是在使用过程往住会发生莫名其妙的崩溃,体 ...
- C++顺序表(模板总结)
C++顺序表(模板总结) 总结: 1.模板类的实质是什么:让程序员写出和类型无关的代码 2.模板的对象时什么:方法或者类 3.是对类中的一系列操作,提供一个不固定数据类型的方法 用模板做的类的时候要指 ...
- Java-JRE:JRE百科
ylbtech-Java-JRE:JRE百科 JRE是Java Runtime Environment缩写,指Java运行环境,是Sun的产品.运行JAVA程序所必须的环境的集合,包含JVM标准实现及 ...
- LA6878
区间dp dp[i][j]存i->j区间的所有取值 然后枚举分割点,枚举两个存的值,分别运算存储. 看见这种不确定分割顺序,两个区间合并的情况,就要用区间dp. #include<bits ...