如果你反编译过异步方法(我非常希望你会这么做),会看到状态机中的 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. 零基础学python-4.2 其它内建类型

    这一章节我们来聊聊其它内建类型 1.类型type 在python2.2的时候,type是通过字符串实现的,再后来才把类型和类统一 我们再次使用上一章节的图片来说明一些问题 我们通过对照上面的图片.在p ...

  2. IntelliJ IDEA 16 EAP新特性一览

    IntelliJ IDEA 16 EAP新特性一览 作者:chszs,未经博主同意不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs IntelliJ I ...

  3. POJ 3370 Halloween treats 鸽巢原理 解题

    Halloween treats 和POJ2356差点儿相同. 事实上这种数列能够有非常多,也能够有不连续的,只是利用鸽巢原理就是方便找到了连续的数列.并且有这种数列也必然能够找到. #include ...

  4. Mac关闭Iphone更新系统iTunes强制自动备份文件

    在任何时候iOS设备一连结苹果Mac电脑,电脑中的iTunes软件将自动对iOS设备进行同步和备份.虽然备份非常有用,当我们的iPhone/iPad出现问题的时候,可以直接恢复iPhone/iPad的 ...

  5. 哈理工2015暑假集训 zoj 2975 Kinds of Fuwas

    G - Kinds of Fuwas Time Limit:2000MS    Memory Limit:65536KB    64bit IO Format:%lld & %llu Subm ...

  6. codeforces Looksery Cup 2015 D. Haar Features

    The first algorithm for detecting a face on the image working in realtime was developed by Paul Viol ...

  7. Ubuntu下在Eclipse IDE for C/C++ Developers中怎样执行C语言的GTK程序?(已解决)

    (已解决.详见Ubuntu 12.04下在Eclipse IDE for C/C++ Developers中执行C语言的GTK程序) 按"Ubuntu下GTK的安装.编译和測试"( ...

  8. B1786 [Ahoi2008]Pair 配对 逆序对+dp

    这个题有点意思,一开始没想到用dp,没啥思路,后来看题解才恍然大悟:k才1~100,直接枚举每个-1点的k取值进行dp就行了.先预处理出来sz[i][j]  i左边的比j大的数,lz[i][j]  i ...

  9. 杂项:ESB接口

    ylbtech-杂项:ESB接口 ESB全称为Enterprise Service Bus,即企业服务总线.它是传统中间件技术与XML.Web服务等技术结合的产物.ESB提供了网络中最基本的连接中枢, ...

  10. El表达式日期处理

    第1步:引入指令  <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt " %&g ...