如果你反编译过异步方法(我非常希望你会这么做),会看到状态机中的 MoveNext() 方法 非常长,变化非常快,像是一个计算有多少 await 表达式的函数。它包含原始方法中的所有逻辑, 和处理所有状态变换所需要的芭蕾舞步 ① ,以及用来处理整个结果或异常的包装代码。

  在手动编写异步代码时,你通常会将后续操作分散到多个方法内:在一个方法内开始,然后 在另一个方法内继续,并且可能在第三个方法中结束。但这样很难处理循环等流控制,对C#编译 器来说更是不可能的。这和生成代码的可读性差是两码事。状态机具有单独的入口,即 MoveNext() 方法。该方法在一开始便投入使用,并且可用于所有 await 表达式的后续操作。每当调用 MoveNext() 方法时,状态机就会通过 state 字段计算出方法要跳转到的位置。在准备计算结果 时,则跳转到方法的逻辑起始位置或 await 表达式的末尾。每个状态机只执行一次操作。实际上, 在方法内部存在一个基于 state 的 switch 语句,每种情况都具有包含不同标签的对应 goto 语句。

MoveNext() 方法一般为以下形式:

             void IAsyncStateMachine.MoveNext()
{
//对于声明返回Task<int>的异步方法
int result = default(int);
try
{
bool doFinallyBodies = true;
switch (state)
{
//跳转到正确的位置
}
//方法主体
}
catch (Exception e)
{
state = -;
builder.SetException(e);
return;
}
state = -;
builder.SetResult(result);
}

  初始状态始终为 -1 ,方法执行时状态也是 -1 (与等待时被暂停相反)。非负值均表示一个后 续操作的目标。状态机在结束时状态为 -2 。在调试配置下创建的状态机中,你会看到一个指向 -3 状态的引用——此状态是我们未曾预料到的。退化的 switch 语句会导致糟糕的调试体验,而 -3 状态即是为避免该退化语句的出现而存在的。

  在方法执行过程中,在原始异步方法的 return 语句处,会设置 result 变量。然而在到达方 法的逻辑末尾时,将其用于 builder.SetResult() 的调用。即使是非泛型的 AysncTask MethodBuilder 和 AsyncVoidMethodBuilder 类型,也包含 SetResult() 方法。前者表示对 于从骨架方法返回的任务来说,该方法已经完成;后者则表示原始的 SynchronizationContext 已经完成。(异常会以同样的方式向原始的 SynchronizationContext 传播。这是一种相当丑陋 的跟踪方式,但却对必须使用 void 方法的场景提供了一种解决方案。)

  doFinallyBodies 变量用于计算执行过程离开 try 块的作用域时,原始代码中的 finally 块(包括 using 或 foreach 语句中的隐式 finally 块)是否应该执行。理论上,只有以正常方式 离开 try 块的作用域时,我们才希望执行 finally 块。如果我们只是从之前为awaiter附加了后续 操作的方法中返回,由于该方法逻辑上已经“暂停”了,因此我们不希望再执行 finally 块。 finally 块均位于相关的 try 块之后,并出现在代码方法部分的 Main 主体中。

  从原始异步方法的角度来看,大多方法体都是可识别的。当然,你需要习惯于所有局部变量 都作为状态机的实例变量,但这并不是什么难事。正如你所想的那样,棘手之处是 await 表达式。

15.5.4 【Task实现细节】一个入口搞定一切的更多相关文章

  1. Jquery一个slideToggle搞定div的隐藏与显示

    Jquery一个slideToggle搞定div的隐藏与显示 <!DOCTYPE html> <html> <head> <script src=" ...

  2. 将你的前端应用打包成docker镜像并部署到服务器?仅需一个脚本搞定

    1.前言 前段时间,自己搞了个阿里云的服务器.想自己在上面折腾,但是不想因为自己瞎折腾而污染了现有的环境.毕竟,现在的阿里云已经没有免费的快照服务了.要想还原的话,最简单的办法就是重新装系统.而一旦重 ...

  3. 一个类搞定UIScrollView那些事儿

    前言 UIScrollView可以说是我们在日常编程中使用频率最多.扩展性最好的一个类,根据不同的需求和设计,我们都能玩出花来,当然有一些需求是大部分应用通用的,今天就聊一下以下需求,在一个categ ...

  4. 一个包搞定中文数据集: datasetstore

    工作中,总是要使用各种中文数据集,每次使用数据集都要花费不少的时间进行寻找,写预处理代码,结合不同的模型和框架做出相应的处理.有的时候好不容易找到合适的数据集,但是却因为网络问题,无法下载,下载了很长 ...

  5. 如何让两个div在同一行显示?一个float搞定

    最近在学习div和css,遇到了一些问题也解决了很多以前以为很难搞定的问题.比如:如何让两个div显示在同一行呢?(不是用table表格,table对SE不太友好)其实,<div> 是一个 ...

  6. iOS之下拉放大,上推缩小,一个方法搞定

    先来看看效果吧. 讲讲大概的实现思路:1、创建头部的视图和tableview,需要注意的是tableview要设置contentInset,contentInsent 的顶部要和头部视图的背景图的高度 ...

  7. 收不到Win10正式版预订通知?一个批处理搞定

    目前,已经有不少Win7.Win8.1用户在系统右下角收到Win10正式版的预订提示窗口.点击接受预订后,系统会将Win10正式版所需的安装文件提前下载好,7月29日正式发布的时候,就可以第一时间升级 ...

  8. 一个类搞定UIScrollView那些事

    前言 UIScrollView可以说是我们在日常编程中使用频率最多.扩展性最好的一个类,根据不同的需求和设计,我们都能玩出花来,当然有一些需求是大部分应用通用的,今天就聊一下以下需求,在一个categ ...

  9. H5 拖拽,一个函数搞定,直接指定对象设置可拖拽

    页面上,弹个小窗体,想让它可以拖拽,又不想 加载一堆js,就简单的能让他可以拖动? 嗯,下面有这样一个函数,调用下就好了! 1. 先来说说 H5的 拖拽 在 HTML5 中,拖放是标准的一部分,任何元 ...

随机推荐

  1. mybatis原理流程

    无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点: 从配置文件(通常是XML配置文件中)得到 sessionfactory. 由sessionfactory  产生 ses ...

  2. iOS: 导航栏显示默认后退按钮

    要显示系统默认的后退按钮(非自定义)的语句如下: [[self navigationController] setNavigationBarHidden:NO animated:YES];self.n ...

  3. MySQL:解决MySQL无法启动的问题

    MySQL无法启动的原因有多种,这里是我遇到的一种情况和解决方法. 起因: 最近项目需要使用MySQL,于是想在MAC上安装一个本地的数据库,但是其实忘了已经安装过一个版本了,结果发现新的服务器怎么也 ...

  4. android 添加一个按键键值【转】

    本文转载自:http://blog.csdn.net/u012719256/article/details/52526046 1.frameworks/base/data/keyboards/Gene ...

  5. Get Length 使用dynamic关键字

    http://www.codewars.com/kata/566f571ed78037c7b6000036/train/csharp You don't have any idea what is t ...

  6. 初识Java,Java语言概述

    Java语言是SUN(斯坦福大学网络公司)公司1995年推出的一门高级编程语言,由此James Gosling被公认为Java语言之父.Java语言起初运用在小型的家用电子产品上,后来随着互联网的发展 ...

  7. CMMI的SG/GG概念区别与SP/GP概念的区别

    每一个 “流程区域” 会细分为多个子目标.若该子目标只对应单一的流程区域,称为 “特定目标(Specific goal)”:若子目标会涵跨多个流程区域,则称为 “一般目标(Generic goal)” ...

  8. php 关于使用七牛云存储

    1.首先注册七牛云存储账号 http://www.qiniu.com/ 2.获得密钥 3.仔细查看文档 http://developer.qiniu.com/docs/v6/sdk/php-sdk.h ...

  9. 【BZOJ3456】城市规划

    题目 转送门 思路&算法 我们设点数为\(n\)的简单图的数量为\(f_n\), 点数为\(n\)的简单连通图有\(g_i\)个 于是我们知道,从\(n\)个点中选\(2\)个点有\(n \c ...

  10. Python 32 通信循环 连接循环 粘包问题

    一:通信循环 二:连接循环 三:粘包问题