async、await原理

目录

一、写一个获取网页内容的方法调用项目

二、结论

三、为什么 C# 要把 async() 方法拆分为多个状态,然后用状态机的方式调用呢

1.验证

2.结论 


一、写一个获取网页内容的方法调用项目

 在这些代码运行的时候,实际上编译器帮我们生成了两个 Main() 方法,一个返回值为 viod 类型,一个返回值为 Task 类型。

返回值为 void 类型的 Main()方法调用了返回值为 Task 类型的 Main() 方法。用了 Result 和 wait() 手段。

扫描二维码关注公众号,回复: 16974749 查看本文章

而异步 Main() 方法在执行的时候实际上编译成了不同的形式运行,它生成了一个类,然后给变量赋值。它把我们定义的变量都编译生成了这个类的成员变量等一系列操作,它把我们写的代码切割成了一个个小步骤,放入了 MoveNext() 方法里面的 try-cath() 方法里面的 case 中去。在返回值为 void 的 Main() 方法中调用了 Start 方法。

MoveNext() 方法会被调用多次 每一次根据 try-cach() 方法中 num 数字的不同执行不同的 case 代码块。

二、结论

async、await 就是一个语法糖。语法糖就是 C# 编译器会把它编译成一个我们用的时候很甜,编译出来的东西比较难,最终编译成状态机调用。

async 会被 C# 编译称为一个类,主要会根据 await 调用进行切分为多个状态,对 async 的调用会被拆分为对 MoveNext() 的调用。 

await 看似是等待,实际被编译后并没有“等待”。是通过对代码的拆分实现“等待”这个行为的。

三、为什么 C# 要把 async() 方法拆分为多个状态,然后用状态机的方式调用呢

await 调用的等待期间,.Net 会把当前的线程返回给线程池,等异步方法调用执行完毕后框架会在线程池再取出来一个线程执行后续的代码。

也就是说在执行异步方法前后执行的线程可能不是同一个线程,await 会导致线程的停止和重新启动的动作。

1.验证

构建一个非常大的字符串:

Thread.CurrentThread.ManagedThreadId 获得当前线程Id。验证:在耗时异步(写入大写字符串)操作前后分别打印线程 Id 。

2.结论 

执行结果为:

 由此验证了结论。

用之前餐馆点餐的例子来解释说,给客人餐单让客人点餐,服务员再去忙别的事,等客人点好餐,服务员再来服务这个客人,而这个时候来哦服务员不一定就是最开始的那位了,由此来说也好理解。但是如果写入的内容较少,也会发现 Id 不变的情况,因为 await 等待的时间少,线程转换较快,所以线程不会变化。

在不影响系统并发的前提下,能避免线程切换就避免线程切换。

猜你喜欢

转载自blog.csdn.net/2201_75837601/article/details/128489570