谈到栈帧(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实现细节】跟踪栈的更多相关文章

  1. 15.5.3 【Task实现细节】状态机的结构

    状态机的整体结构非常简单.它总是使用显式接口实现,以实现.NET 4.5引入的 IAsync StateMachine 接口,并且只包含该接口声明的两个方法,即 MoveNext 和 SetState ...

  2. 15.5.2 【Task实现细节】骨架方法的结构

    尽管骨架方法中的代码非常简单,但它暗示了状态机的职责.代码清单15-11生成的骨架方 法如下所示: [DebuggerStepThrough] [AsyncStateMachine(typeof(De ...

  3. 15.5.5 【Task实现细节】围绕 await 表达式的控制

    任何 await 表达式均表示执行路径的一个分支.首先,被等待的异步操作得到一个awaiter,然后检查其 IsCompleted 属性.若返回 true ,即可立即获得结果并继续.否则,需进行以下处 ...

  4. 15.5.4 【Task实现细节】一个入口搞定一切

    如果你反编译过异步方法(我非常希望你会这么做),会看到状态机中的 MoveNext() 方法 非常长,变化非常快,像是一个计算有多少 await 表达式的函数.它包含原始方法中的所有逻辑, 和处理所有 ...

  5. 15.5.1【Task实现细节】 生成的代码

    还在吗?我们开始吧.由于深入讲解需上百页的篇幅,因此这里我不会讲得太深.但我会提 供足够的背景知识,以有助于你对整个结构的理解.之后可通过阅读我近些年来撰写的博客文章, 来了解更加错综复杂的细节,或简 ...

  6. android的task任务栈

    转自http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀 ...

  7. Activity的task任务栈

    转自http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀 ...

  8. 细说Activity与Task(任务栈)

    Task概要: task是一个具有栈结构的容器,可以放置多个Activity实例.启动一个应用,系统就会为之创建一个task,来放置根Activity:默认情况下, 一个Activity启动另一个Ac ...

  9. Apache Flink:特性、概念、组件栈、架构及原理分析

     2016-04-30 22:24:39    Yanjun Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,它能够基于同一个Flink运行时(Flink Runtim ...

随机推荐

  1. Android 开发 ContentProvider 获取歌曲列表和联系人的样例

    ContentProvider(内容提供者)是Android中的四大组件之中的一个. 主要用于对外共享数据.也就是通过ContentProvider把应用中的数据共享给其它应用訪问.其它应用能够通过C ...

  2. [Windows]_[0基础]_[Release程序的崩溃报告minidump解决方式]

    场景: 1. Release的程序崩溃时,崩溃报告能够让开发者查明代码哪里出了问题,用处大大的. 2. 仅仅实用VS的编译器才支持,所以MinGW就无缘了. 3. 使用了未处理异常过滤处理函数. 4. ...

  3. Android---keycode值以及相应名称

    KEYCODE列表 电话键 键名 描写叙述 键值   KEYCODE_CALL 拨号键 5 KEYCODE_ENDCALL 挂机键 6 KEYCODE_HOME 按键Home 3 KEYCODE_ME ...

  4. luogu1631 序列合并

    题目大意 有两个序列A,B,在A和B中各取一个数相加能得到$n^2$个和.求出这些和前n小的数字. 题解 首先这道题不可以用自己想的什么A序列B序列各两个指针的自己发明的模拟算法,用这样的算法只能是绝 ...

  5. Linux 中的键盘映射【转】

    本文转载自:http://hessian.cn/p/144.html [转]Linux 中的键盘映射 原文地址:http://www.linuxidc.com/Linux/2011-04/35197. ...

  6. C# winform 组件---- folderBrowserDialog与openFileDialog(转)

    C# winform 组件---- folderBrowserDialog与openFileDialog 2009-06-27 13:36 2153人阅读 评论(1) 收藏 举报 winformc#b ...

  7. B1607 [Usaco2008 Dec]Patting Heads 轻拍牛头 数学

    今天净做水题了,这个题还不到十五分钟就搞定了,思路特别简单,就是直接按照线性求因子个数的思路就行了. 题干: Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜 ...

  8. iOS获取相册/相机图片-------自定义获取图片小控件

    一.功能简介 1.封装了一个按钮,点击按钮,会提示从何处获取图片:如果设备支持相机,可以从相机获取,同时还可以从手机相册获取图片. 2.选择图片后,有一个block回调,根据需求,将获得的图片拿来使用 ...

  9. Python 38 sql基础

    数据库服务器中存放的是 库(文件加)  .表(文件) .表里面是记录(一行数据) 增     删     改     查 1.库相关 创建------------------create databa ...

  10. Spring-Boot配置文件数据源配置项

    Spring-Boot配置文件数据源配置项(常用配置项为红色) 参数 介绍 spring.datasource.continue-on-error = false 初始化数据库时发生错误时,请勿停止 ...