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 ...
随机推荐
- 机器学习10k均值
下面介绍无监督机器学习算法,与前面分类回归不一样的是,这个不知道目标变量是什么,这个问题解决的是我们从这些样本中,我们能发现什么. 这下面主要讲述了聚类算法,跟数据挖掘中的关联挖掘中的两个主要算法. ...
- JS 带运动的返回顶部 小案例
带运动的返回顶部:当滚动条在滚动的时候,滚动鼠标的滚轮,应该让滚动条停止滚动,清掉定时器.下面的方法b 就是清掉的方法 <!DOCTYPE html PUBLIC "-//W3C//D ...
- HDU 1561&HDU 3449 一类简单依赖背包问题
HDU 1561.这道是树形DP了,所谓依赖背包,就是选A前必须选B,这样的问题.1561很明显是这样的题了.把0点当成ROOT就好,然后选子节点前必须先选根,所以初始化数组每一行为该根点的值.由于多 ...
- gcc动态链接库so的制作和使用
http://blog.csdn.net/CSqingchen/article/details/51546784 参考: http://blog.sina.com.cn/s/blog_69e96b37 ...
- Xsolla与蜗牛一起共创黑金
Xsolla和蜗牛游戏强强合作,公布了黑金在线,是中国知名网络游戏武术时代的一个新项目. Xsolla与蜗牛黑金 2014年6月10日至20日,蜗牛的黑金在线首次在美国洛杉矶E3展会上亮相. 该游戏官 ...
- HDU4638:Group(线段树离线处理)
Problem Description There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and ...
- oc64--协议2@protocol
// // SportProtocol.h // day17 // #import <Foundation/Foundation.h> @protocol SportProtocol &l ...
- oc53--autorelease注意事项
// // main.m // autorelease注意事项 #import <Foundation/Foundation.h> #import "Person.h" ...
- codeforce1046 Bubble Cup 11 - Finals 题解
比赛的时候开G开了3h结果rose说一句那唯一一个AC的是羊的心态就崩了.. 这套题感觉质量挺好然后就back了下 A: AI robots 有三个限制条件:相互能够看见和智商的差.使用主席树,可以维 ...
- Sqlserver 数据库恢复常见错误及解决(网站转载 留着备用)
数据库恢复常见错误及解决 2009-04-13 11:25 1145人阅读 评论(0) 收藏 举报 数据库databasesqlserverusermicrosoftsql server 在sqlSe ...