分享更有价值
被信任是一种快乐

如何理解Await与Async

文章页正文上

这篇文章主要介绍“如何理解Await与Async ”,在日常操作中,相信很多人在如何理解Await与Async 问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Await与Async ”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!一:背景1. 讲故事await,async 这玩意的知识点已经被人说的烂的不能再烂了,看似没什么好说的,但我发现有不少文章还是从理论上讲述了这两个语法糖的用法,懂得还是懂,不懂的看似懂了过几天又不懂了,人生如戏全靠记是不行的哈,其实本质上来说 await, async 只是编译器层面上的语法糖,在 IL 层面都会被打成原型的,所以在这个层面上认识这两个语法糖是非常有必要的。二:从 IL 层面认识1. 使用 WebClient 下载为了方便打回原型,我先上一个例子,使用 webclient 异步下载 http://cnblogs.com 的html,代码如下:上面的代码非常简单,可以看到异步操作没有阻塞主线程输出: 稍等… 正在下载 cnblogs -> html rn, 编译器层面没什么好说的 ,接下来看下在 IL 层面发生了什么?2. 挖掘 await async 的IL代码还是老规矩, ilSpy 走起,如下图:可以看到,这里有一个 GetResult 方法 ,一个 Main 方法,还有一个不知道在哪里冒出来的d__1 类,接下来和大家一个一个聊。 d__1> 类因为不知道从哪里冒出来的,特别引人关注,所以看看它的 IL 是咋样的?从上面的 IL 代码可以看到,这是自动生成的d__1 类实现了接口 IAsyncStateMachine,定义如下:看到里面的 MoveNext 是不是很眼熟,平时你在 foreach 集合的时候就会用到这个方法,那时人家叫做枚举类,在这里算是被改造了一下, 叫状态机???。 GetResult ()为了方便演示,我对方法体中的 IL 代码做一下简化:如果你稍微懂一点的话,在 IL_0000 处的 newobj 你就应该知道这个方法就是做了 newd__1,然后从 IL_002b 处返回了一个 get_Task() ,这时候你就应该明白,为什么主线程不会被阻塞,因为人家返回的免费云主机、域名是 Task,对吧,最后的 http 结果会藏在 Task中,这样是不是就很好理解了。 MainMain方法没有做任何改变,原来是什么样现在还是什么样。三:将 IL 代码 回写为 C#1. 完整 C# 代码通过前面一部分你应该对 await ,async 在 IL 层面有了一个框架性的认识,这里我就全部反写成 C# 代码:可以看到,回写成 C# 代码之后跑起来是没有任何问题的,为了方便理解,我先来画一张流程图。通过上面的 xmind,它基本流程就是: stateMachine.builder.Start(ref stateMachine) -> GetResult.MoveNext -> client.DownloadStringTaskAsync -> localAwaiter.IsCompleted = false -> builder.AwaitUnsafeOnCompleted(ref localAwaiter, ref stateMachine) -> GetResult.MoveNext -> localAwaiter.GetResult() -> builder.SetResult(result)2. 剖析 AsyncTaskMethodBuilder其实你仔细观察会发现,所谓的 await,async 的异步化运作都是由 AsyncTaskMethodBuilder 承载的,如异步任务的启动,对html结果的封送,接触底层IO,其中 Task对应着 AsyncTaskMethodBuilder, Task 对应着 AsyncTaskMethodBuilder, 这也是为什么编译器在 async 处一直提示你返回 Task 和 Task,如果不这样的话的就找不到对应 AsyncTaskMethodBuilder 了,对吧,如下图:然后着重看下 AwaitUnsafeOnCompleted 方法,这个方法非常重要,其注释如下:一旦调用了这个方法,就需要等待 底层IO 将任务处理完毕之后二次回调 GetResult.MoveNext,也就表示要么异常要么完成任务, Awaiter 包装的 Task 结果封送到 builder.SetResult。然后简单说一下 状态机 的走法,通过调试会发现这里会走 两次 MoveNext,一次启动,一次拿结果。 第一次回调 MoveNext第一次 MoveNext 的触发由 stateMachine.builder.Start(ref stateMachine) 发起,可以用 dnspy 去调试一下,如下图: 第二次回调 MoveNext第二次 MoveNext 的触发由 builder.AwaitUnsafeOnCompleted(ref localAwaiter, ref stateMachine) 开始,可以看到一旦 网络驱动程序 处理完毕后就由线程池IO线程主动发起到最后触发代码中的 MoveNext,最后就是到 awaiter 中获取 task 的 result 处结束,如下图:到此,关于“如何理解Await与Async ”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注云技术网站,小编会继续努力为大家带来更多实用的文章!

相关推荐: react中less不起作用怎么解决

今天小编给大家分享一下react中less不起作用怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。 解决方法:1、利用“npm insta…

文章页内容下
赞(0) 打赏
版权声明:本站采用知识共享、学习交流,不允许用于商业用途;文章由发布者自行承担一切责任,与本站无关。
文章页正文下
文章页评论上

云服务器、web空间可免费试用

宝塔面板主机、支持php,mysql等,SSL部署;安全高速企业专供99.999%稳定,另有高防主机、不限制内容等类型,具体可咨询QQ:360163164,Tel同微信:18905205712

主机选购导航云服务器试用

登录

找回密码

注册