C# Async await底层源码阅读

前前言

原文博客链接
由于CSDN界面越来越烂,因此自己搭建了一个博客网站,上面的链接是我自己的个人博客网站地址,希望大家可以去上面阅读我的文章,CSDN只是用来备份数据

http://www.lizhenghao.site/blog/2022/01/12/152

个人的博客首页:

博客首页

前言

对于我来说,Task+await+async已经用的很熟练了,像之前也写过一篇文章http://www.lizhenghao.site/blog/2021/12/30/89 讲了一下怎么用Task和TaskFactory实现限制并行任务数量的多线程操作,但是自己对底层的实现机制一直比较懵懂,下面自己写个demo再用dnspy看一下源码(dnspy,永远滴神!

来个demo

internal class Program
{
	static async Task Main(string[] args)
	{
		Console.WriteLine("begin");
		await Task.Run(() =>
					   {
						   Console.WriteLine("inside");
						   Thread.Sleep(5000);
					   });
		Console.WriteLine("end");
		while (true)
		{
			Thread.Sleep(1000);
			Console.WriteLine("Wait 1 second");
		}
	}
}

首先来段非常简单的代码,下面我们用dnspy看一下反编译后的代码情况

注意这里如果用ilspy得把环境调整到C# 1.0版本,否则版本太高直接给反编译的跟源代码一样了,如果是用dnspy,记得在设置里把反编译异步方法、反编译匿名方法、反编译表达树这些选项关掉,否则反编译之后很难看明白

file

下面我们先一段一段把这个代码进行分解,半蒙半猜来推导一下这里面实现了啥逻辑

file

首先上来Main函数,基本原先的代码就被改的面目全非了,经过一番分析后,发现首先是在原本的Program内部插入了一个内部类<Main>d__0,这里我们就叫它状态机类吧,因为这个类继承了IAsyncStateMachine接口,从这个接口的名字也可以很容易就猜出来了,其实async await的实现机制就是靠状态机,再往下看,就是调用了一个builder成员的Start方法,这里暂且不管这个Start内部啥逻辑,我们就知道传入的是一个状态机类的对象,接下来我们单步调试一下看看start之后调用到了哪里:

file

没想到程序一运行调用的竟然是<Main>而不是Main,不知道为啥,但是也不重要了,看下面调用的堆栈和当前的断点位置我们会发现,果然在Start之后就进入了MoveNext函数,好了,下面再来分析一下MoveNext函数干了啥

file

具体的流程看上图中的注释就可以猜个大概了,下面就是这个AwaitUNSageOnCompleted这个函数看不懂是干啥的,还好有注释

file

简单翻译下,就是说在awaiter完成的之后调用状态机的MoveNext函数继续执行,我们还是看一下里面具体是咋实现的

file

这下也很容易理解了,其实await就是把整个await这个函数里面的代码分成了三个部分:

file

先执行了await之前的代码,之后用Task执行内部的代码,立刻return,直到await内的代码执行完了再执行await后面的代码

我们再修改一下我们的demo,像下面这个样子:

file

在await之前我先输出一段日志到控制台,接着再await,我们看一下反编译后的源码是啥样子:

file

!!!竟然是直接把await之前的代码全部放到return之前去执行了…因此函数内部的分界线就是看await在什么地方。

总结一下

  1. async、await内部其实是靠状态机机制实现的,在await之前的代码执行完了之后就把对应Task完成的事件订阅一下,在事件触发时再次修改状态,从而执行MoveNext的下面await之后的代码。
  2. 为啥不会卡主线程?主要是在Task.Run之后直接return了,把后面的代码放到了下次再调用MoveNext的时候执行,这个执行的线程在控制台应用程序时不一定是主线程,而在WPF、Winform等带UI的项目中,是由主线程来完成后续逻辑执行的,这一点也是我自己实验过的。

关于以上的所有思路,都是靠自己阅读了一下源码了解的,如果有错误的地方欢迎指出

  1. https://www.youtube.com/watch?v=il9gl8MH17s 这里推荐一下我在油管搜到的一个讲async await很好的视频,推荐大家也去学习一下,视频长度25分钟
  2. 还有朝夕教育的Eleven老师也有个录播讲 Async await源码, 就是视频比较长,估计2,3小时,如果需要百度云资源的可以留言我,晚上下班了可以发你学习一下
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值