15.5.6 【Task实现细节】跟踪栈
谈到栈帧(stack frame)时,可能会想到在方法中声明的局部变量。当然,可能还会注意到 一些隐藏的局部变量,如 foreach 循环中的迭代器。但栈上的内容不止这些,至少逻辑上是这样 。 很多情况下,在一些表达式还没有计算出来前,另一些中间表达式是不能使用的。最简单的例子 莫过于加法等二进制操作和方法调用了。 举个极简单的例子,思考下面这一行:
var x = y * z;
在基于栈的伪代码中,将为如下形式:
push y
push z
multiply
store
现在假设有如下 await 表达式:
var x = y * await z;
在等待 z 之前,需计算 y 并将其保存至某处,但可能会从 MoveNext() 方法立即返回,因此需 要一个逻辑栈来存储 y 。在执行后续操作时,可以重新存储该值,然后执行乘法。在这种情况下, 编译器可将 y 的值赋值给 stack 实例变量。这会引起装箱,但同时也意味着可以使用单个变量。 这是个简单的例子。假设有多个值需要存储,如下所示:
Console.WriteLine("{0} :{1}", x, await task);
在逻辑栈上需要存储格式化的字符串和 x 值。此时编译器会创建一个包含两个值的Tuple<string, int> ,并将其存储在 stack 的引用上。和 awaiter 一样,同一时间只需要一个逻辑栈,因此一直使用相同的变量是没有问题的。在后续操作中,可以从元组(tuple)中获取
实参,并用于方法调用。可下载的源代码中包含了完整的反编译示例,其中包括以上两条语句( LogicalStack.cs 和 LogicalStackDecompiled.cs )。
第二条语句最终将使用以下代码:
string localArg0 = "{0} {1}";
int localArg1 = x;
localAwaiter = task.GetAwaiter();
if (localAwaiter.IsCompleted)
{
goto SecondAwaitCompletion;
}
var localTuple = new Tuple<string, int>(localArg0, localArg1);
stack = localTuple;
state = ;
awaiter = localAwaiter;
builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
doFinallyBodies = false;
return;
SecondAwaitContinuation:
localTuple = (Tuple<string, int>) stack;
localArg0 = localTuple.Item1;
localArg1 = localTuple.Item2;
stack = null;
localAwaiter = awaiter;
awaiter = default(TaskAwaiter<int>);
state = -;
SecondAwaitCompletion:
int localArg2 = localAwaiter.GetResult();
Console.WriteLine(localArg0, localArg1, localArg2);
此处加粗显示的是与逻辑栈元素相关的代码。 目前所有需了解的内容均已介绍完毕。如果你跟上了我们的步伐,就肯定比99%的开发者更 为了解背后的细节。第一次没能完全理解也没有关系。在阅读这些状态机代码时,如果感到无法 理清头绪,可以暂时放松一下,过一会儿再来继续学习。
15.5.6 【Task实现细节】跟踪栈的更多相关文章
- 15.5.3 【Task实现细节】状态机的结构
状态机的整体结构非常简单.它总是使用显式接口实现,以实现.NET 4.5引入的 IAsync StateMachine 接口,并且只包含该接口声明的两个方法,即 MoveNext 和 SetState ...
- 15.5.2 【Task实现细节】骨架方法的结构
尽管骨架方法中的代码非常简单,但它暗示了状态机的职责.代码清单15-11生成的骨架方 法如下所示: [DebuggerStepThrough] [AsyncStateMachine(typeof(De ...
- 15.5.5 【Task实现细节】围绕 await 表达式的控制
任何 await 表达式均表示执行路径的一个分支.首先,被等待的异步操作得到一个awaiter,然后检查其 IsCompleted 属性.若返回 true ,即可立即获得结果并继续.否则,需进行以下处 ...
- 15.5.4 【Task实现细节】一个入口搞定一切
如果你反编译过异步方法(我非常希望你会这么做),会看到状态机中的 MoveNext() 方法 非常长,变化非常快,像是一个计算有多少 await 表达式的函数.它包含原始方法中的所有逻辑, 和处理所有 ...
- 15.5.1【Task实现细节】 生成的代码
还在吗?我们开始吧.由于深入讲解需上百页的篇幅,因此这里我不会讲得太深.但我会提 供足够的背景知识,以有助于你对整个结构的理解.之后可通过阅读我近些年来撰写的博客文章, 来了解更加错综复杂的细节,或简 ...
- android的task任务栈
转自http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀 ...
- Activity的task任务栈
转自http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀 ...
- 细说Activity与Task(任务栈)
Task概要: task是一个具有栈结构的容器,可以放置多个Activity实例.启动一个应用,系统就会为之创建一个task,来放置根Activity:默认情况下, 一个Activity启动另一个Ac ...
- Apache Flink:特性、概念、组件栈、架构及原理分析
2016-04-30 22:24:39 Yanjun Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,它能够基于同一个Flink运行时(Flink Runtim ...
随机推荐
- POJ 2960
也算是一道模板题吧,只需按照SG函数的定义求出每个值的SG,然后异或就可以了. #include <iostream> #include <cstdio> #include & ...
- 2.3-STP生成树
2.3-STP生成树 单点失效(signle point of failure)及其解决方法: 当两个Segement之间只有一条物理连接时就有可能出现单点失效→ 单方面的故障导致全网 ...
- [Vue-rx] Access Events from Vue.js Templates as RxJS Streams with domStreams
The domStreams component property enables you to access Events from your Vue.js templates as Streams ...
- MFC 小知识总结四
1 PlaySound 播放WAV格式的音乐 This function plays a sound specified by a file name, resource, or system ev ...
- Hive权限之审计
因为在生产环境中大量使用hive.而hive的权限又较弱,假设可以记录全部hive操作,在增强安全性的同一时候,还可以统计hive表的使用频率:同一时候假设可以记录hql的開始和结束时间,则可以找出系 ...
- Apache OFbiz service engine 源代码解读
上一篇看完了ofbiz entity engine,这篇再来过一下ofbiz的service engine.service engine层在设计模式的使用上跟entity engine有些相似,最典型 ...
- Python字符串转为字典方法大全
方法一: 通过内置函数eval str_info = '{"name": "test", "age": 18}' dict_info = e ...
- JDK框架简析--java.lang包中的基础类库、基础数据类型
题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...
- C++_homework_EraseComment
顾名思义就是删除程序中的注释,不清楚fsm的机制,完全是自己的思路做. 开头先读取一个字符确定是否到文件结尾,如果读取成功,是换行的话就换行,并继续读取,不是的话,用putback放回缓冲区,并整行读 ...
- 纯CSS 实现关闭图标 icon
本文介绍关闭 icon 的实现.具体如下 1.html部分 <span id="close"></span> 2.css部分 #close { displa ...