尽管骨架方法中的代码非常简单,但它暗示了状态机的职责。代码清单15-11生成的骨架方 法如下所示:

         [DebuggerStepThrough]
[AsyncStateMachine(typeof(DemoStateMachine))]
static Task<int> SumCharactersAsync(IEnumerable<char> text)
{
var machine = new DemoStateMachine();
machine.text = text;
machine.builder = AsyncTaskMethodBuilder<int>.Create();
machine.state = -;
machine.builder.Start(ref machine);
return machine.builder.Task;
}

  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来设 置结果或异常。

     class DecompilationSampleDecompiled
{
static void Main()
{
Task<int> task = SumCharactersAsync("test");
Console.WriteLine(task.Result);
} [DebuggerStepThrough]
[AsyncStateMachine(typeof(DemoStateMachine))]
static Task<int> SumCharactersAsync(IEnumerable<char> text)
{
var machine = new DemoStateMachine();
machine.text = text;
machine.builder = AsyncTaskMethodBuilder<int>.Create();
machine.state = -;
machine.builder.Start(ref machine);
return machine.builder.Task;
} [CompilerGenerated]
private struct DemoStateMachine : IAsyncStateMachine
{
// Fields for parameters
public IEnumerable<char> text; // Fields for local variables
public IEnumerator<char> iterator;
public char ch;
public int total;
public int unicode; // Fields for awaiters
private TaskAwaiter taskAwaiter;
private YieldAwaitable.YieldAwaiter yieldAwaiter; // Common infrastructure
public int state;
public AsyncTaskMethodBuilder<int> builder;
private object stack; void IAsyncStateMachine.MoveNext()
{
int result = default(int);
try
{
bool doFinallyBodies = true;
switch (state)
{
case -:
goto Done;
case :
goto FirstAwaitContinuation;
case :
goto SecondAwaitContinuation;
}
// Default case - first call (state is -1)
total = ;
iterator = text.GetEnumerator(); // We really want to jump straight to FirstAwaitRealContinuation, but we can't
// goto a label inside a try block...
FirstAwaitContinuation:
// foreach loop
try
{
// for/foreach loops typically have the condition at the end of the generated code.
// We want to go there *unless* we're trying to reach the first continuation.
if (state != )
{
goto LoopCondition;
}
goto FirstAwaitRealContinuation;
LoopBody:
ch = iterator.Current;
unicode = ch;
TaskAwaiter localTaskAwaiter = Task.Delay(unicode).GetAwaiter();
if (localTaskAwaiter.IsCompleted)
{
goto FirstAwaitCompletion;
}
state = ;
taskAwaiter = localTaskAwaiter;
builder.AwaitUnsafeOnCompleted(ref localTaskAwaiter, ref this);
doFinallyBodies = false;
return;
FirstAwaitRealContinuation:
localTaskAwaiter = taskAwaiter;
taskAwaiter = default(TaskAwaiter);
state = -;
FirstAwaitCompletion:
localTaskAwaiter.GetResult();
localTaskAwaiter = default(TaskAwaiter);
total += unicode;
LoopCondition:
if (iterator.MoveNext())
{
goto LoopBody;
}
}
finally
{
if (doFinallyBodies && iterator != null)
{
iterator.Dispose();
}
} // After the loop
YieldAwaitable.YieldAwaiter localYieldAwaiter = Task.Yield().GetAwaiter();
if (localYieldAwaiter.IsCompleted)
{
goto SecondAwaitCompletion;
}
state = ;
yieldAwaiter = localYieldAwaiter;
builder.AwaitUnsafeOnCompleted(ref localYieldAwaiter, ref this);
doFinallyBodies = false;
return; SecondAwaitContinuation:
localYieldAwaiter = yieldAwaiter;
yieldAwaiter = default(YieldAwaitable.YieldAwaiter);
state = -;
SecondAwaitCompletion:
localYieldAwaiter.GetResult();
localYieldAwaiter = default(YieldAwaitable.YieldAwaiter);
result = total;
}
catch (Exception ex)
{
state = -;
builder.SetException(ex);
return;
}
Done:
state = -;
builder.SetResult(result);
} [DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine machine)
{
builder.SetStateMachine(machine);
}
}
}

最新文章

  1. Eclipse 调试技巧
  2. [django]l利用xlrd实现xls文件导入数据
  3. 布局 - panel
  4. C#分布式缓存二:Asp.Net中使用Couchbase
  5. 解决plsql工具不能用中文字进行模糊匹配
  6. java中判断从数据库中取出的字段是否为空
  7. sp_getTable_data
  8. UI学习笔记---第十四天数据持久化
  9. Android_Intent_passValue(4)
  10. ios真机调试详细步骤
  11. js实现键盘操作对div的移动或改变-------Day43
  12. 团队作业8----第二次项目冲刺(Beta阶段) 第三天
  13. ●BZOJ 2154 Crash的数字表格
  14. Java Class Version 研究
  15. Android--Task和BackStack高级
  16. Vue+koa2开发一款全栈小程序(7.图书录入功能)
  17. js中循环对比(for循环,foreach,for in,for of ,map)
  18. Jmeter之正则表达式提取器应用
  19. docker 常用命令(一)
  20. 关于vue,webpack 中 “exports is not defined”报错

热门文章

  1. [转]十五天精通WCF——第八天 对“绑定”的最后一点理解
  2. 前台JSON字符串,spring mvc controller也接收字符串
  3. 设置ckeditor的高度
  4. vijos - P1279Leave-绿光(数学归纳法 + python)
  5. iOS APP开发概述----学习笔记001
  6. C#如何读写和创建INI文件(经典)转
  7. Codeforces--630A--Again Twenty Five! (水题)
  8. PCB Genesis加二维码 实现方式
  9. bzoj1725 [Usaco2006 Nov]Corn Fields牧场的安排(状压dp)
  10. bzoj1030 文本生成器(AC自动机+dp)