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 ...
随机推荐
- N天学习一个Linux命令之ln
前言有时候同一个文件想创建多个别名,这个时候可以使用链接文件代替 用途对文件或者目录创建链接,默认创建的是硬链接 硬链接Linux底层文件系统由超级数据块,目录树对象,inode索引节点对象,文件对象 ...
- 学习C#和SQL的书籍
1. <21天学通C#> 周红安等编著 电子工业出版社 2. http://blog.csdn.net/21aspnet/article/details/1682200 3. < ...
- 2014 北京 DevFest 大会能够报名啦,小伙伴们还在等什么
一年一度的大型开发人员活动,2014 北京 DevFest 大会站点正式上线: http://devfest.gdgbeijing.org/. 还等什么,開始报名了! 今年 DevFest 大会将再次 ...
- sql server 2008安装图解
本篇文章介绍了安装SQL Server 2008企业版的软硬件配置要求,安装过程的具体步骤,以及须要注意的事项. 步骤/方法 1 在这里我们将用图解的方式.来介绍SQL Server 2008安装和配 ...
- 使用Carthage安装及使用第三方库
CocoaPods 安装不了,只好使用Carthage 参考:http://www.jianshu.com/p/52dff4cef8a2 http://www.jianshu.com/p/bf263c ...
- opencv源代码分析之二:cvhaartraining.cpp
我使用的是opencv2.4.9.安装后.我的cvboost..cpp文件的路径是........\opencv\sources\apps\haartraining\cvhaartraining.cp ...
- luogu1070 道路游戏 单调队列
题目大意 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 nn 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 nn 个机器人工 ...
- c# 命令行下编译c#文件 // c# file类读写文件
c# 命令行下编译c#文件 2010-03-01 15:02:14| 分类: c# 学习|字号 订阅 在 开始 ——>程序 ——>vstool中打开vs2008命令提示. 通过 ...
- 【POJ 3635】 Full Tank
[题目链接] http://poj.org/problem?id=3635 [算法] 优先队列BFS 实现类似于堆优化dijkstra [代码] #include <algorithm> ...
- 杂项:ASP.NET Web API
ylbtech-杂项:ASP.NET Web API ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务. ASP.NET Web A ...