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
15.5.2 【Task实现细节】骨架方法的结构相关推荐
- 15.5.1【Task实现细节】 生成的代码
还在吗?我们开始吧.由于深入讲解需上百页的篇幅,因此这里我不会讲得太深.但我会提 供足够的背景知识,以有助于你对整个结构的理解.之后可通过阅读我近些年来撰写的博客文章, 来了解更加错综复杂的细节,或简 ...
- 使用 EasyBCD 安装Ubuntu 14.04 Error 15: file not found错误的解决方法
使用 EasyBCD 安装Ubuntu 14.04 Error 15: file not found错误的解决方法 参考文章: (1)使用 EasyBCD 安装Ubuntu 14.04 Error 1 ...
- 计算机组装需要注意什么东西,电脑DIY:电脑组装时应该注意的几个细节以及方法...
大家好,我是余生,在之前几期文章中给大家讲解了组装电脑的硬件的挑选以及性能,那么本期内容给大家讲解一下电脑组装过程中一些需要注意的地方,喜欢的朋友可以支持下小编,点点关注哦! 电脑DIY:电脑组装时应 ...
- 常用的表格检测识别方法——表格结构识别方法 (下)
常用的表格检测识别方法--表格结构识别方法(下) 3.2表格结构识别方法 表格结构识别是表格区域检测之后的任务,其目标是识别出表格的布局结构.层次结构等,将表格视觉信息转换成可重建表格的结构描述信息. ...
- 常用的表格检测识别方法——表格结构识别方法(上)
第三章 常用的表格检测识别方法 3.2表格结构识别方法 表格结构识别是表格区域检测之后的任务,其目标是识别出表格的布局结构.层次结构等,将表格视觉信息转换成可重建表格的结构描述信息.这些表格结构描述信 ...
- 简单介绍C语言使用四种方法初始化结构体
这篇文章说明了什么是结构体,介绍了结构体的概念和使用优点,在C语言中如何使用和初始化结构体方法,通过详细的代码展开进行说明,希望该篇文章对你有所帮助 什么是结构体 在实际问题中,一组数据往往有很多种不 ...
- Golang——结构体创建与初始化、结构体与数组、结构体与切片、结构体与map、结构体作为函数参数、结构体方法、结构体方法继承
结构体: 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合 结构体可以很好的管理一批有联系的数据,使用结构体可以提高程序的易读性,类似于Java的类一样 不能在结构体直接赋值 字段名必须唯一 ...
- 15篇论文全面概览BERT压缩方法
作者 | Mitchell A. Gordon 译者 | 孙薇 出品 | AI科技大本营(ID:rgznai100) 模型压缩可减少受训神经网络的冗余--由于几乎没有BERT或者BERT-Large模 ...
- 避免野指针的方法及结构体小细节
避免野指针的方法 1 定义指针变量的时候,指针变量赋值成NULL 2 释放的时候,判断是不是NULL 3 释放完毕以后再赋值成NULL 结构体小细节 typedef struct _Teacher{ ...
最新文章
- 即时通讯 TCP UDP
- POJ 3322 Bloxorz I(BFS)
- python3爬虫入门实例_10个python爬虫入门实例(小结)
- 整体二分初识--POJ2104:K-th Number
- Python3入门机器学习经典算法与应用 第3章 numpy 聚合操作
- 微软 虚拟学院 官方 Introduction to Microsoft Dynamics CRM 2013 视频学习地址分享
- 黄渤海浅层气的分布及特征综述
- mysql分级建表_Mysql如何使用命令实现分级查找帮助详解
- 矩阵的 Jordan 标准型
- 《人性的枷锁》读后感范文4500字
- 【学习笔记】欧拉筛法(线性筛素数)
- 在线成语接龙答题有奖微信小程序源码V1.5.1
- 【数据库】--- Redis
- 今日头条怎么申请开通原创,怎么快速过新手期
- Error creating document instance
- 是时候复习一下响应式设计了
- 短视频抖音电商编导剧本分镜拍摄内容策划脚本计划表格方案模板
- 干盘管蒸发冷-间接蒸发冷的终结者?-孙长青
- Keil错误 error: #5: cannot open source input file XXX / XXX.h:
- 信息收集[端口CDNWAF]
热门文章
- fpga在线升级 linux_仅5000行Verilog代码、可在FPGA上跑轻量级Linux系统的RISC-V内核
- 每天一道LeetCode-----数独盘求解
- nbu还原oracle,NBU恢复oracle
- Shell(4)——测试test、[]、逻辑、||文件-f、-d、-x、-eq、-gt、-ge、-lt、-le、-ne
- Xcode 9 新建的工程如何支持 iOS 8
- LINK:fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- 动态添加XtraTabControl
- 正则表达式matches_正则表达式在VBA中间是如何应用?正则表达式的实现方式?...
- 关于tensorflow和keras那些事儿
- 删除副本列表中的消失项目符号