zoukankan      html  css  js  c++  java
  • 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 = text;
     7             machine.builder = AsyncTaskMethodBuilder<int>.Create();
     8             machine.state = -1;
     9             machine.builder.Start(ref machine);
    10             return machine.builder.Task;
    11         }

      AsyncStateMachineAttribute 类型是为 async 引入的新特性(attribute)之一。它是为工具而设计的,你自己并不会有机会消费这个特性,并且也不应该在自己的方法上应用这个特性。
    我们已经在这个状态机上看到了三个字段。
     一个是参数( text )。显然有多少个参数就会有多少个字段。
     一个是 AsyncTaskMethodBuilder<int> 。该结构负责将状态机和骨架方法联系在一起。对于仅返回 Task 的方法,存在对应的非泛型类。对于返回 void 的方法,可以使用AsnycVoidMethodBuilder 结构。
     一个是 state ,值从 -1 开始。初始值永远为 -1 ,稍后我们会介绍其他值的含义。

      由于状态机是一个结构(struct), AsyncTaskMethodBuilder<int> 也是一个结构,因此我 们还没有执行任何堆分配。当然,完全可以让执行的不同调用在堆上进行分配,但有必要指出的 是,代码在尽可能地避免这么做。异步的本质意味着,如果哪个 await 表达式需要真正的等待, 你会需要很多这种值(在堆上),但代码保证了它们只会在需要的时候进行装箱。所有这些都属 于实现细节,就像堆和栈属于实现细节一样,但为了让 async 能够适用于尽可能多的场景,微软 的相关团队紧密合作,将分配降低到了绝对最小值。

      对 machine.builder.Start(ref machine) 的调用非常有意思。这里使用了按引用传递, 以避免创建状态机的复本(以及builder的复本),这是出于性能和正确性两方面的考虑。编译器 非常愿意将状态机和builder视为类,因此 ref 可以在代码中自由地使用。为了使用接口,不同的 方法将builder(或awaiter)作为参数,使用泛型类型参数,并限定其实现某个接口(如对于状态 机来说就是 IAsyncStateMachine )。这样在调用接口的成员时,就不需要任何装箱了。方法的 行为描述起来非常简单——它让状态机同步地执行第一个步骤,并在方法完成时或到达需等待的 异步操作点时得以返回。

      第一个步骤完成后,骨架方法将返回builder中的任务。状态机在结束时,会使用builder来设 置结果或异常。

      1     class DecompilationSampleDecompiled
      2     {
      3         static void Main()
      4         {
      5             Task<int> task = SumCharactersAsync("test");
      6             Console.WriteLine(task.Result);
      7         }
      8 
      9         [DebuggerStepThrough]
     10         [AsyncStateMachine(typeof(DemoStateMachine))]
     11         static Task<int> SumCharactersAsync(IEnumerable<char> text)
     12         {
     13             var machine = new DemoStateMachine();
     14             machine.text = text;
     15             machine.builder = AsyncTaskMethodBuilder<int>.Create();
     16             machine.state = -1;
     17             machine.builder.Start(ref machine);
     18             return machine.builder.Task;
     19         }
     20 
     21         [CompilerGenerated]
     22         private struct DemoStateMachine : IAsyncStateMachine
     23         {
     24             // Fields for parameters
     25             public IEnumerable<char> text;
     26 
     27             // Fields for local variables
     28             public IEnumerator<char> iterator;
     29             public char ch;
     30             public int total;
     31             public int unicode;
     32 
     33             // Fields for awaiters
     34             private TaskAwaiter taskAwaiter;
     35             private YieldAwaitable.YieldAwaiter yieldAwaiter;
     36 
     37             // Common infrastructure
     38             public int state;
     39             public AsyncTaskMethodBuilder<int> builder;
     40             private object stack;
     41 
     42             void IAsyncStateMachine.MoveNext()
     43             {
     44                 int result = default(int);
     45                 try
     46                 {
     47                     bool doFinallyBodies = true;
     48                     switch (state)
     49                     {
     50                         case -3:
     51                             goto Done;
     52                         case 0:
     53                             goto FirstAwaitContinuation;
     54                         case 1:
     55                             goto SecondAwaitContinuation;
     56                     }
     57                     // Default case - first call (state is -1)
     58                     total = 0;
     59                     iterator = text.GetEnumerator();
     60 
     61                 // We really want to jump straight to FirstAwaitRealContinuation, but we can't
     62                 // goto a label inside a try block...
     63                 FirstAwaitContinuation:
     64                     // foreach loop
     65                     try
     66                     {
     67                         // for/foreach loops typically have the condition at the end of the generated code.
     68                         // We want to go there *unless* we're trying to reach the first continuation.
     69                         if (state != 0)
     70                         {
     71                             goto LoopCondition;
     72                         }
     73                         goto FirstAwaitRealContinuation;
     74                     LoopBody:
     75                         ch = iterator.Current;
     76                         unicode = ch;
     77                         TaskAwaiter localTaskAwaiter = Task.Delay(unicode).GetAwaiter();
     78                         if (localTaskAwaiter.IsCompleted)
     79                         {
     80                             goto FirstAwaitCompletion;
     81                         }
     82                         state = 0;
     83                         taskAwaiter = localTaskAwaiter;
     84                         builder.AwaitUnsafeOnCompleted(ref localTaskAwaiter, ref this);
     85                         doFinallyBodies = false;
     86                         return;
     87                     FirstAwaitRealContinuation:
     88                         localTaskAwaiter = taskAwaiter;
     89                         taskAwaiter = default(TaskAwaiter);
     90                         state = -1;
     91                     FirstAwaitCompletion:
     92                         localTaskAwaiter.GetResult();
     93                         localTaskAwaiter = default(TaskAwaiter);
     94                         total += unicode;
     95                     LoopCondition:
     96                         if (iterator.MoveNext())
     97                         {
     98                             goto LoopBody;
     99                         }
    100                     }
    101                     finally
    102                     {
    103                         if (doFinallyBodies && iterator != null)
    104                         {
    105                             iterator.Dispose();
    106                         }
    107                     }
    108 
    109                     // After the loop
    110                     YieldAwaitable.YieldAwaiter localYieldAwaiter = Task.Yield().GetAwaiter();
    111                     if (localYieldAwaiter.IsCompleted)
    112                     {
    113                         goto SecondAwaitCompletion;
    114                     }
    115                     state = 1;
    116                     yieldAwaiter = localYieldAwaiter;
    117                     builder.AwaitUnsafeOnCompleted(ref localYieldAwaiter, ref this);
    118                     doFinallyBodies = false;
    119                     return;
    120 
    121                 SecondAwaitContinuation:
    122                     localYieldAwaiter = yieldAwaiter;
    123                     yieldAwaiter = default(YieldAwaitable.YieldAwaiter);
    124                     state = -1;
    125                     SecondAwaitCompletion:
    126                     localYieldAwaiter.GetResult();
    127                     localYieldAwaiter = default(YieldAwaitable.YieldAwaiter);
    128                     result = total;
    129                 }
    130                 catch (Exception ex)
    131                 {
    132                     state = -2;
    133                     builder.SetException(ex);
    134                     return;
    135                 }
    136             Done:
    137                 state = -2;
    138                 builder.SetResult(result);
    139             }
    140 
    141             [DebuggerHidden]
    142             void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine machine)
    143             {
    144                 builder.SetStateMachine(machine);
    145             }
    146         }
    147     }
  • 相关阅读:
    线段树 by yyb
    【SYZOJ279】滑稽♂树(树套树)
    【BZOJ2806】Cheat(后缀自动机,二分答案,动态规划,单调队列)
    【BZOJ2733】永无乡(线段树,并查集)
    【BZOJ4991】我也不知道题目名字是什么(线段树)
    【BZOJ4999】This Problem Is Too Simple!(线段树)
    【BZOJ1858】序列操作(线段树)
    【BZOJ1835】基站选址(线段树)
    【BZOJ2962】序列操作(线段树)
    【BZOJ1558】等差数列(线段树)
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10128089.html
Copyright © 2011-2022 走看看