zoukankan      html  css  js  c++  java
  • 15.5.1【Task实现细节】 生成的代码

      还在吗?我们开始吧。由于深入讲解需上百页的篇幅,因此这里我不会讲得太深。但我会提 供足够的背景知识,以有助于你对整个结构的理解。之后可通过阅读我近些年来撰写的博客文章, 来了解更加错综复杂的细节,或简单地编写一些异步代码并反编译。同样地,这里我只介绍异步 方法,它包含了所有有趣的机制,并且不需要处理异步匿名函数所处的间接层。

      说明 警告,勇敢的旅行者—— 前方是实现细节! 本节将描述微软C# 5编译器(随着.NET 4.5的发布而推出)内实现的相关内容。从CTP版到beta版,有些细节变化很大,并且在未 来仍有可能发生改变。但我认为其基本理念并不会发生太大的变动。充分了解本节内容 后,你会发现并不存在什么魔法,只不过是一些编译器生成的聪明代码罢了。这之后便 可以从容应对未来变化的细节内容了。 正如我之前多次提到过的,它的实现(包括近似实现和真实编译器生成的代码)基本上可以 说是一个状态机。编译器将生成一个私有的内嵌结构,来表示这个异步方法。这个结构还必须包 含一个方法,其签名与所声明的方法签名相同。我称其为骨架方法,该方法本身没有多少内容, 但其他东西都依赖于它。

      骨架方法需要创建状态机,并执行一个步骤(此处的步骤指执行第一个 await 表达式之前的 代码),然后返回一个表示状态机进度的任务。(别忘了,在第一次到达真正需要等待的 await 表 达式之前,执行过程是同步的。)此后,骨架方法的运作就此结束。状态机会负责其余事项,后 续操作附加到其他异步操作后,可通知状态机去执行另一个步骤。当之前返回的任务被赋予适当 的值后,方法就执行到最后了, 状态机可随即发出信号。

      当然,“执行方法体中的代码”这一步,只有在骨架方法中第一次调用时,才会从方法的开 头执行。以后每次到达该块,都是由后续操作从之前中断的地方开始继续执行。 现在有两个概念需要关注,即骨架方法和状态机。在本节的剩余篇幅中,我将使用单个异步 方法作为示例,如代码清单15-11所示。

     1         static async Task<int> SumCharactersAsync(IEnumerable<char> text)
     2         {
     3             int total = 0;
     4             foreach (char ch in text)
     5             {
     6                 int unicpde = ch;
     7                 await Task.Delay(unicpde);
     8                 total += unicpde;
     9             }
    10             await Task.Yield();
    11             return total;
    12         }

    代码清单15-11没有什么实际意义,但我们只关注流控制。在开始之前,有必要指出以下几点。
     该方法包含一个参数( text )。
     该方法包含一个循环,后续操作执行时需跳回该循环内。
     该方法包含两个不同类型的 await 表达式: Task.Delay 返回一个 Task ,而 Task.Yield()则返回一个 YieldAwaitable 。
     该方法包含显式的局部变量( total 、 ch 和 unicode ),需在不同的调用间关注其变化。
     该方法包含一个通过调用 text.GetEnumerator() 方法创建的隐式局部变量。
     该方法最终返回一个值。
    这段代码最初的版本将 text 作为 string 类型的参数,但C#编译器会对字符串的迭代进行优
    化,并使用 Length 属性和索引器,这会使反编译后的代码变得更加复杂。

  • 相关阅读:
    ubuntu系统安装初始化脚本
    21_多线程
    20_IO
    19_异常
    18_集合
    17_内部类和常用类
    16_接口
    15_abstract,static,final
    14_面向对象
    13_数组
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10128004.html
Copyright © 2011-2022 走看看