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 )。

  第二条语句最终将使用以下代码:

 1                     string localArg0 = "{0} {1}";
 2                     int localArg1 = x;
 3                     localAwaiter = task.GetAwaiter();
 4                     if (localAwaiter.IsCompleted)
 5                     {
 6                         goto SecondAwaitCompletion;
 7                     }
 8                     var localTuple = new Tuple<string, int>(localArg0, localArg1);
 9                     stack = localTuple;
10                     state = 1;
11                     awaiter = localAwaiter;
12                     builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
13                     doFinallyBodies = false;
14                     return;
15                 SecondAwaitContinuation:
16                     localTuple = (Tuple<string, int>) stack;
17                     localArg0 = localTuple.Item1;
18                     localArg1 = localTuple.Item2;
19                     stack = null;
20                     localAwaiter = awaiter;
21                     awaiter = default(TaskAwaiter<int>);
22                     state = -1;
23                 SecondAwaitCompletion:
24                     int localArg2 = localAwaiter.GetResult();
25                     Console.WriteLine(localArg0, localArg1, localArg2);

此处加粗显示的是与逻辑栈元素相关的代码。 目前所有需了解的内容均已介绍完毕。如果你跟上了我们的步伐,就肯定比99%的开发者更 为了解背后的细节。第一次没能完全理解也没有关系。在阅读这些状态机代码时,如果感到无法 理清头绪,可以暂时放松一下,过一会儿再来继续学习。

原文地址:https://www.cnblogs.com/kikyoqiang/p/10128305.html

时间: 2024-10-20 16:19:26

15.5.6 【Task实现细节】跟踪栈的相关文章

9.4 Java的异常跟踪栈

异常对象的printStackTTrace()方法用于打印异常的跟踪栈信息,根据printStackTTrace()方法输出的结果,开发者可以找到异常的源头,并跟踪到异常一路触发的过程. 下面测试printStackTrace的例子: class SelfException extends RuntimeException { SelfException(){} SelfException(String msg) { super(msg); } } public class printStack

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

尽管骨架方法中的代码非常简单,但它暗示了状态机的职责.代码清单15-11生成的骨架方 法如下所示: 1 [DebuggerStepThrough] 2 [AsyncStateMachine(typeof(DemoStateMachine))] 3 static Task<int> SumCharactersAsync(IEnumerable<char> text) 4 { 5 var machine = new DemoStateMachine(); 6 machine.text

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

状态机的整体结构非常简单.它总是使用显式接口实现,以实现.NET 4.5引入的 IAsync StateMachine 接口,并且只包含该接口声明的两个方法,即 MoveNext 和 SetStateMachine . 此外,它还拥有大量私有或公共字段. 状态机的声明在折叠后如代码清单15-11所示: 1 [CompilerGenerated] 2 private struct DemoStateMachine : IAsyncStateMachine 3 { 4 // Fields for p

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

还在吗?我们开始吧.由于深入讲解需上百页的篇幅,因此这里我不会讲得太深.但我会提 供足够的背景知识,以有助于你对整个结构的理解.之后可通过阅读我近些年来撰写的博客文章, 来了解更加错综复杂的细节,或简单地编写一些异步代码并反编译.同样地,这里我只介绍异步 方法,它包含了所有有趣的机制,并且不需要处理异步匿名函数所处的间接层. 说明 警告,勇敢的旅行者—— 前方是实现细节! 本节将描述微软C# 5编译器(随着.NET 4.5的发布而推出)内实现的相关内容.从CTP版到beta版,有些细节变化很大,

python中利用tracekback跟踪栈以及打印异常信息

?##sys.exc_info() 返回 (type, value, traceback). type为异常类型, value为异常的参数(通常为异常错误的信息), traceback为跟踪回溯的对象. exc_type, exc_value, exc_traceback = sys.exc_info() print "*** print sys.exc_info:" print 'exc_type is: %s, exc_value is: %s, exc_traceback is:

android的task任务栈

转自http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀書示子聿(yù)> 软件行业也是一样,多少前辈不遗余力的奋斗才出现了软件行业的繁荣的景象,其中已有不少成为大师级人物.今天我们站在伟人的肩膀上,自然会有不少的优势,但不要忘了,要在对技术的认知方面有所提升,仍需我们去实践,去实践. 今天我们来讲一下Activity的task相关内容. 上次我们讲到Act

深入理解Activity启动流程(四)–Activity Task的调度算法

本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启动的概要流程 深入理解Activity启动流程(二)--Activity启动相关类的类图 深入理解Activity启动流程(三)--Activity启动的详细流程1 深入理解Activity启动流程(三)--Activity启动的详细流程2 前面两篇博客介绍了Activity的详细启动流程,提到ActivityStack类的startActivityU

java实现栈与队列

一.栈 栈是一种特殊的线性表.其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行.(先进后出) 访问权限:栈限制了访问权限,只可以访问尾节点,也就是最后添加的元素 即栈顶的元素 1 /** 2 * 栈 先进后出 3 * @author Administrator 4 * 5 */ 6 public class MyStack { 7 private long [] arr; 8 private int top; 9 public MyStack(){ 10 arr=new long[

基础总结篇之三:Activity的task相关

古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀書示子聿(yù)> 软件行业也是一样,多少前辈不遗余力的奋斗才出现了软件行业的繁荣的景象,其中已有不少成为大师级人物.今天我们站在伟人的肩膀上,自然会有不少的优势,但不要忘了,要在对技术的认知方面有所提升,仍需我们去实践,去实践. 今天我们来讲一下Activity的task相关内容. 上次我们讲到Activity的四种启动模式的时候,已经了解到一些关于task的技术,今天我再向大家介绍一下.task是一个具有栈结