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     }

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

时间: 2024-10-23 05:46:48

15.5.2 【Task实现细节】骨架方法的结构的相关文章

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版,有些细节变化很大,

Error:Execution failed for task &#39;:app:transformClassesWithDexForDebug&#39;解决方法

Error:Execution failed for task ':app:transformClassesWithJarMergingForDebug'. > com.android.build.transform.api.TransformException: java.util.zip.ZipException: duplicate entry: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 类似问题我通过审查build.gradle引用的lib,把所有功能重复

androidstudio打包时出现错误Error:Execution failed for task &#39;:app:transformClassesWithDexForRelease&#39;解决方法

今天在android studio上打包项目时,遇到了Error:Execution failed for task ':app:transformClassesWithDexForRelease这么个错误,记得之前也遇到过这种问题,却如何想不起怎么解决的,只好再次在网上查资料,总算是解决了 这个问题的原因倒是简单的很,是因为我项目中应用的jar包重复,我在build.gradle文件的dependencies中重复依赖了libs下的jar包,将下边的删除即可 androidstudio打包时出

深入解析 ObjC 中方法的结构

因为 ObjC 的 runtime 只能在 Mac OS 下才能编译,所以文章中的代码都是在 Mac OS,也就是 x86_64 架构下运行的,对于在 arm64 中运行的代码会特别说明. 在上一篇分析 isa 的文章从 NSObject 的初始化了解 isa中曾经说到过实例方法被调用时,会通过其持有 isa 指针寻找对应的类,然后在其中的 class_data_bits_t 中查找对应的方法,在这一篇文章中会介绍方法在 ObjC 中是如何存储方法的. 这篇文章的首先会根据 ObjC 源代码来分

15.5.6 【Task实现细节】跟踪栈

谈到栈帧(stack frame)时,可能会想到在方法中声明的局部变量.当然,可能还会注意到 一些隐藏的局部变量,如 foreach 循环中的迭代器.但栈上的内容不止这些,至少逻辑上是这样  . 很多情况下,在一些表达式还没有计算出来前,另一些中间表达式是不能使用的.最简单的例子 莫过于加法等二进制操作和方法调用了. 举个极简单的例子,思考下面这一行: var x = y * z; 在基于栈的伪代码中,将为如下形式: push y push z multiply store 现在假设有如下 aw

避免野指针的方法及结构体小细节

避免野指针的方法 1 定义指针变量的时候,指针变量赋值成NULL 2 释放的时候,判断是不是NULL 3 释放完毕以后再赋值成NULL 结构体小细节 typedef struct _Teacher{ char name[64];//64 int age;//4 char tile[128];//128 char c;//1 }Teacher,*pTeacher; 以上定义了一个结构体变量,结构体变量所占字节数理论上应该是197(64+4+128+1) void main() { Teacher

线程 task 使用三种方法

1:用TaskFactory的实例: 运行结果为: 2. 使用task类的Factory属性 3.使用task类的实例,用start来启动任务.  当我们用Task类时,除了用start方法,也可以用RunSynchornously()方法 原文地址:https://www.cnblogs.com/bingyizhihun/p/8251681.html

ovs加dpdk在日志中查看更多运行细节的方法

想查看更多dpdk+ovs的更多运行细节,可以采用以下方法,增加更多运行日志. 在终端输入: ovs-appctl vlog/set dpdk:file:dbg ovs-appctl vlog/set netdev_dpdk:file:dbg 并查看 ovs-vswitchd.logs(在/usr/local/var/log/openvswitch目录下) ,便可以查看更多运行细节. 原文地址:https://www.cnblogs.com/vancasola/p/9406564.html