• 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%的开发者更 为了解背后的细节。第一次没能完全理解也没有关系。在阅读这些状态机代码时,如果感到无法 理清头绪,可以暂时放松一下,过一会儿再来继续学习。

  • 相关阅读:
    XPath中的text()和string()区别(转)
    (转)Ubuntu 16.04 安裝Docker(PS:本文适用amd64位的ubuntu系统)
    python 爬取世纪佳缘,经过js渲染过的网页的爬取
    Python中的join()函数的用法
    Ubuntu下修改ubuntu源,完成Redis Desktop Manager的安装
    Ubuntu16.04安装Redis
    Scrapy爬虫实例教程(二)---数据存入MySQL
    Ubuntu16.04安装mongodb 及使用
    关闭和启动网卡
    网络之端口的作用
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10128305.html
Copyright © 2020-2023  润新知