async/await 贴脸输出,这次你总该明白了

1543d5875131d2c7a705ecc974bd1148.gif
出来混总是要还的

最近在准备.NET Go核心能力的深度对比.note, 关于.NET/Go的异步实现总感觉没敲到点上。

async/await是.NET界老生常谈的话题,每至于此,状态机又是必聊的话题,但是状态机又是比较晦涩难懂的话题。

[一线码农大佬]在博客园2020年写的《await,async 我要把它翻个底朝天,这回你总该明白了吧[1]》手把手实现了异步状态机,这篇文章很是经典, 但是评论区很多人还是在吐槽看不懂, 我也看的不是很懂。

以我浅薄的推测:

  1. 1. 一线大佬的知识体系太宽太深,有的验证点在文字之外,需要我们自己去确认。

  2. 2. 有些内容太细节,挖的太深,出不来。

  3. 3. 很多人不熟悉状态机设计模式, 导致看大佬文章,知其然不知其所以然。

  4. 本次延续一线码农原始demo,记录我的理解。

我以前用Go语言演示了状态机: 我是状态机,有一颗永远骚动的机器引擎[2], 当时有粉丝留言让用.NET 实现状态机, 这篇文章也算是对粉丝的喊话。

状态机:一颗永远骚动的机器引擎

状态机是一种行为设计模式,它允许对象在其内部状态改变时改变其行为,对象看起来好像修改了它的类。

请仔细理解上面每一个字。

我们以自动售货机为例,为简化演示,我们假设自动售货机只有1种商品, 故自动售货机有itemCount 、itemPrice 2个属性

不考虑动作的前后相关性,自动售货机对外暴露4种行为:

  • • 给自动售货机加货 addItem

  • • 选择商品 requestItem

  • • 付钱 insertMoney

  • • 出货 dispenseItem

重点来了,当发生某种行为,自动售货机会进入如下4种状态之一, 并据此状态做出特定动作, 之后进入另外一种状态.....

  • • 有商品 hasItem

  • • 无商品 noItem

  • • 已经选好商品 itemRequested

  • • 已付钱 hasMoney

7cd1fde97e3d0490b290fc5d44b0e23a.png

当对象可能处于多种不同的状态之一、根据传入的动作更改当前的状态, 继续接受后续动作,状态再次发生变化.....

这样的模式类比于机器引擎,周而复始的工作和状态转化,这也是状态机的定语叫“机Machine”的原因。

有了以上思路,我们尝试沟通UML 伪代码

e59730d54da4d631869114ae383aa66f.png

状态机设计模式的伪代码实现:

  • • 所谓的机器Machine维护了状态切换的上下文

  • • 机器对外暴露的行为,驱动机器的状态变更

  • • 机器到达特定的状态 只具备特定的行为,其他行为是不被允许的

Go版本的售货机(状态机设计模式)的源码,请参见原文https://www.cnblogs.com/JulianHuang/p/15304184.html。

async/await贴脸输出

还是以一线码农大佬的异步下载为例:

3ea773ce95410768dd928ba0a3ddab57.png

编译器词法分析定位到async/await语法糖,就会为开发者生成状态机代码。

一个新出炉的状态机包含如下属性 :

9f4af303800b4eb8a53a95cec95c4394.png

(1) 初始化的状态机,以async所在的函数名命名,示例状态机为<GetResult>d__1

(2) 车钥匙启动状态机之后,立马返回,这正是异步编程的内涵。

一个简单的、成功的状态机轮转图(很重要、很重要、很重要):

6decf01472f18eda83af99663c80131e.png
1. 初始状态
  • • state= -1;

  • • Start状态机;即时返回。

Program.<GetResult>d__1 stateMachine = new Program.<GetResult>d__1();
stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start<Program.<GetResult>d__1>(ref stateMachine);
return stateMachine.<>t__builder.Task;

用车钥匙Start,内部实际是执行MoveNext方法[3], 该方法会设置等待异步任务完成TaskAwaiter对象, 紧接着stateMachine切换到新的状态。

2. 异步任务未完成状态
  • • 切换到state = 0

  • • 调用AwaitUnsafeOnCompleted()向底层注册回调, 2个入参[4]

    • • 回调参数1:等待异步任务结果的对象TaskAwaiter<TResult>

    • • 回调参数2:当前状态机

int num1 = this.<>1__state;

if (num1 != 0)
{
    this.<client>5__1 = new WebClient();
    awaiter = this.<client>5__1.DownloadStringTaskAsync(new Uri("http://cnblogs.com")).GetAwaiter();
   if (!awaiter.IsCompleted)
  {
      this.<>1__state = num2 = 0;
      this.<>u__1 = awaiter;
      Program.<GetResult>d__1 stateMachine = this;
     this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, Program.<GetResult>d__1>(ref awaiter, ref stateMachine);
      return;
  }
}

IO数据就绪,会在IO线程执行回调方法GetCompletionAction,利用入参2:状态机,再次执行状态机的MoveNext方法, 进入新的状态。

3. 异步结果就绪状态
  • • 切换到state = -1;

  • • taskAwaiter获取异步任务结果;

  • • 执行后继代码;

else
{
    awaiter = this.<>u__1;
    this.<>u__1 = new TaskAwaiter<string>();
    this.<>1__state = num2 = -1;
}
this.<>s__3 = awaiter.GetResult();
this.<content>5__2 = this.<>s__3;
this.<>s__3 = (string) null;
content52 = this.<content>5__2;   // 后继代码段
若过程无异常的,进入状态机终止状态。
4. 状态机终止状态
  • • 切换到state =-2;

  • • 设置状态机最终返回值;

this.<>1__state = -2;
this.<client>5__1 = (WebClient) null;
this.<content>5__2 = (string) null;
this.<>t__builder.SetResult(content52);

以上四个状态的贴脸源码均截取自ILspy反编译结果,读者可将代码和状态轮转图对比。


一线码农大佬讲:一个简单成功的async/await状态机会经历 2次MoveNext动作 ,我是认同的。

一次是状态机启动时执行,主动切换状态;

第二次是IO数据就绪,回调函数会执行原状态机的MoveNext方法, 这个是在注册回调的时候确定的。

下面是第二次MoveNext方法的执行堆栈(包含github地址):

  • • 第二次StateMachine.MoveNext[5]

    • • GetCompletionAction回调方法[7]

    •     • AwaitUnsafeOnCompleted注册回调[8]

    •          • moveNextRunner.Run()[6];

结束语

本文重点从状态机设计模式的角度,演示了async/await语法糖的内部实现。

通过一个骚动的机器引擎,演示了开启异步任务---> 异步任务完成---> 设置状态机输出结果的状态变迁,而这4个状态的变迁又催生了.NET异步编程的性能优势。

4d102699e328bab4a21687c328f18d12.png

最后:本文是一线码农大佬《异步async/await底朝天》的狗尾续貂,respect !!!

文字和图片均为原创,一家之言,欢迎留言吐槽。

引用链接

[1] 一线码农大佬]在博客园2020年写的《[await,async 我要把它翻个底朝天,这回你总该明白了吧: https://www.cnblogs.com/huangxincheng/p/13558006.html
[2] 我是状态机,有一颗永远骚动的机器引擎: https://www.cnblogs.com/JulianHuang/p/15304184.html
[3] 车钥匙Start,内部实际是执行`MoveNext`方法: https://github.com/OmerMor/AsyncBridge/blob/aa806b61be32363934378ffc2df979dc8b34ea88/src/AsyncBridge/Runtime.CompilerServices/AsyncMethodBuilderCore.cs#L27
[4] `AwaitUnsafeOnCompleted()`向底层注册回调, 2个入参: https://github.com/OmerMor/AsyncBridge/blob/aa806b61be32363934378ffc2df979dc8b34ea88/src/AsyncBridge/Runtime.CompilerServices/AsyncTaskMethodBuilder.cs#L328
[5] 第二次StateMachine.MoveNext: https://github.com/OmerMor/AsyncBridge/blob/aa806b61be32363934378ffc2df979dc8b34ea88/src/AsyncBridge/Runtime.CompilerServices/AsyncMethodBuilderCore.cs#L137
[6] moveNextRunner.Run(): https://github.com/OmerMor/AsyncBridge/blob/aa806b61be32363934378ffc2df979dc8b34ea88/src/AsyncBridge/Runtime.CompilerServices/AsyncMethodBuilderCore.cs#L64
[7] GetCompletionAction回调方法: https://github.com/OmerMor/AsyncBridge/blob/aa806b61be32363934378ffc2df979dc8b34ea88/src/AsyncBridge/Runtime.CompilerServices/AsyncMethodBuilderCore.cs#L59C25-L59C44
[8] AwaitUnsafeOnCompleted注册回调: https://github.com/OmerMor/AsyncBridge/blob/aa806b61be32363934378ffc2df979dc8b34ea88/src/AsyncBridge/Runtime.CompilerServices/AsyncTaskMethodBuilder.cs#L334C50-L334C69

6c6556f5ca021ad58c1ec10870fb8e79.gif

自古以来,同步/异步都是八股文第一章

.NET领域最硬核的gRPC 核心能力一把梭

流量调度、微服务可寻址性和注册中心

Go语言正/反向代理的姿势

两将军问题和TCP三次握手

"家长进校园"之《计算机和人工智能》

6e1797749f05338d7cd6d8ee5b04906f.png

点“ce40137f7e1de0d6eaf17015c94d860f.gif戳“在看80fad445b79ed8d42ae1ec3419876632.gif

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有态度的马甲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值