HTML5技术

C#异步的世界【下】 - 农码一生(4)

字号+ 作者:H5之家 来源:H5之家 2017-03-06 17:06 我要评论( )

class MyAsyncTest{ public async Task string GetUrlStringAsync(HttpClient http, string url, int time){ await Task.Delay(time); return await http.GetStringAsync(url);}} 反编译代码: 点击看大图 为了方便

class MyAsyncTest { public async Task<string> GetUrlStringAsync(HttpClient http, string url, int time) { await Task.Delay(time); return await http.GetStringAsync(url); } }

反编译代码:

点击看大图

为了方便阅读,我们把编译器自动命名的类型重命名。

 GetUrlStringAsync 方法变成了如此模样:

public Task<string> GetUrlStringAsync(HttpClient http, string url, int time) { GetUrlStringAsyncdStateMachine stateMachine = new GetUrlStringAsyncdStateMachine() { _this = this, http = http, url = url, time = time, _builder = AsyncTaskMethodBuilder<string>.Create(), _state = -1 }; stateMachine._builder.Start(ref stateMachine); return stateMachine._builder.Task; }

方法签名完全一致,只是里面的内容变成了一个状态机 GetUrlStringAsyncdStateMachine  的调用。此状态机就是编译器自动创建的。下面来看看神秘的状态机是什么鬼:

GetUrlStringAsyncdStateMachine : IAsyncStateMachine { public int _state; public MyAsyncTest _this; private string _str1; public AsyncTaskMethodBuilder<string> _builder; private TaskAwaiter taskAwaiter1; private TaskAwaiter<string> taskAwaiter2;

//异步方法的三个形参都到这里来了
public HttpClient http; public int time; public string url; private void MoveNext() { string str; int num = this._state; try { TaskAwaiter awaiter; MyAsyncTest.GetUrlStringAsyncdStateMachine d__; string str2; switch (num) { case 0: break; case 1: goto Label_00CD; default:
//这里是异步方法 await Task.Delay(time);的具体实现 awaiter
= Task.Delay(this.time).GetAwaiter(); if (awaiter.IsCompleted) { goto Label_0077; } this._state = num = 0; this.taskAwaiter1 = awaiter; d__ = this; this._builder.AwaitUnsafeOnCompleted<TaskAwaiter, MyAsyncTest.GetUrlStringAsyncdStateMachine>(ref awaiter, ref d__); return; } awaiter = this.taskAwaiter1; this.taskAwaiter1 = new TaskAwaiter(); this._state = num = -1; Label_0077: awaiter.GetResult(); awaiter = new TaskAwaiter();
//这里是异步方法await http.GetStringAsync(url);的具体实现 TaskAwaiter
<string> awaiter2 = this.http.GetStringAsync(this.url).GetAwaiter(); if (awaiter2.IsCompleted) { goto Label_00EA; } this._state = num = 1; this.taskAwaiter2 = awaiter2; d__ = this; this._builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, MyAsyncTest.GetUrlStringAsyncdStateMachine>(ref awaiter2, ref d__); return; Label_00CD: awaiter2 = this.taskAwaiter2; this.taskAwaiter2 = new TaskAwaiter<string>(); this._state = num = -1; Label_00EA: str2 = awaiter2.GetResult(); awaiter2 = new TaskAwaiter<string>(); this._str1 = str2; str = this._str1; } catch (Exception exception) { this._state = -2; this._builder.SetException(exception); return; } this._state = -2; this._builder.SetResult(str); } [DebuggerHidden] private void SetStateMachine(IAsyncStateMachine stateMachine) { } }

明显多个异步等待执行的时候就是在不断调用状态机中的MoveNext()方法。经验来至我们之前分析过的,不过今天的这个明显复杂度要高于以前的那个。猜测是如此,我们还是来验证下事实:

在起始方法 GetUrlStringAsync 第一次启动状态机 stateMachine._builder.Start(ref stateMachine); 

 确实是调用了 MoveNext 。因为_state的初始值是-1,所以执行到了下面的位置:

绕了一圈又回到了 MoveNext 。由此,我们可以现象成多个异步调用就是在不断执行MoveNext直到结束。

说了这么久有什么意思呢,似乎忘记了我们的目的是要通过之前编写的测试代码来分析异步的执行逻辑的。

再次贴出之前的测试代码,以免忘记了。

反编译后代码执行逻辑图:

当然这只是可能性较大的执行流程,但也有 awaiter.Iscompleted 为 true 的情况。其他可能的留着大家自己去琢磨吧。 

 

在此,异步的分析到此结束。由于博主能力有限,某些地方描述不正确,某些避重就轻了。请大家多多包含。当然,欢迎补充!

本文已同步至索引目录:《》

本文demo:https://github.com/zhaopeiym/BlogDemoCode

 

【推荐】

 

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • C#异步的世界【上】 - 农码一生

    C#异步的世界【上】 - 农码一生

    2017-01-18 13:00

  • 那些年搞不懂的术语、概念:协变、逆变、不变体 - 农码一生

    那些年搞不懂的术语、概念:协变、逆变、不变体 - 农码一生

    2016-08-30 17:00

  • 用canvas画简单的“我的世界”人物头像 - 玉菲莎

    用canvas画简单的“我的世界”人物头像 - 玉菲莎

    2016-07-27 14:00

  • JS运动从入门到兴奋1 - 沫晴的前端世界

    JS运动从入门到兴奋1 - 沫晴的前端世界

    2016-07-16 11:00

网友点评