-
.NET异步和多线程系列(六)- async/await
本文是.NET异步和多线程系列的第六章,本章主要对之前介绍过的async/await做一些补充说明。
下面我们直接来看下代码和运行结果:
using System; using System.Threading; using System.Threading.Tasks; namespace MyAsyncAwait { /// <summary> /// await/async 是C#保留关键字,通常是成对出现,语法糖。 /// /// 主线程调用async/await方法,主线程遇到await返回执行后续动作, /// await后面的代码会等着Task任务的完成后再继续执行 /// 其实就像把await后面的代码包装成一个ContinueWith的回调动作 /// 然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程 /// /// 一个async方法,如果没有返回值,可以方法声明返回Task /// await/async能够用同步的方式编写代码,但又是非阻塞的。 /// /// async方法在编译后会生成一个状态机(实现了IAsyncStateMachine接口) /// </summary> class Program { static void Main(string[] args) { Console.WriteLine($"当前主线程开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); AwaitAsyncClass.TestShow(); Console.WriteLine($"当前主线程结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Console.ReadKey(); } } /// <summary> /// await/async关键字 语法糖 /// await/async 要么不用 要么用到底 /// </summary> public class AwaitAsyncClass { public static void TestShow() { Test(); } private async static Task Test() { Console.WriteLine($"Test开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Task<long> t = SumAsync(); Console.WriteLine($"遇到await主线程回来干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); { long lResult = await t; //await后面的代码会由线程池的线程执行,非阻塞。 Console.WriteLine($"最终得到的lResult={lResult}"); } { //t.Wait(); //主线程等待Task的完成,阻塞的 //long lResult = t.Result; //访问Result,主线程等待Task的完成,阻塞的,效果跟t.Wait()一样 //Console.WriteLine($"最终得到的lResult={lResult}"); } Console.WriteLine($"Test结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); } /// <summary> /// 带返回值的Task /// 要使用返回值就一定要等子线程计算完毕 /// </summary> private static async Task<long> SumAsync() { Console.WriteLine($"SumAsync start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); long result = 0; //await后面的代码会等着Task任务的完成后再继续执行 //其实就像把await后面的代码包装成一个ContinueWith的回调动作 //然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程 await Task.Run(() => { for (int k = 0; k < 2; k++) { Console.WriteLine($"SumAsync 第1个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumAsync 第1个 await Task.Run的后续任务开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); await Task.Run(() => { for (int k = 0; k < 2; k++) { Console.WriteLine($"SumAsync 第2个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumAsync 第2个 await Task.Run的后续任务开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); await Task.Run(() => { for (int k = 0; k < 2; k++) { Console.WriteLine($"SumAsync 第3个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumAsync end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return result; } } }
运行结果如下:
仔细观察结果会发现:
主线程调用async/await方法,主线程遇到await后会返回执行后续动作;
await后面的代码会等着Task任务的完成后再继续执行,其实就像把await后面的代码包装成一个ContinueWith的回调动作;
然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程;
await/async能够用同步的方式编写代码,但又是非阻塞的。
下面我们调整下Test方法后再运行(红色的为调整部分):
private async static Task Test() { Console.WriteLine($"Test开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Task<long> t = SumAsync(); Console.WriteLine($"遇到await主线程回来干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); { //long lResult = await t; //await后面的代码会由线程池的线程执行,非阻塞。 //Console.WriteLine($"最终得到的lResult={lResult}"); } { //t.Wait(); //主线程等待Task的完成,阻塞的 long lResult = t.Result; //访问Result,主线程等待Task的完成,阻塞的,效果跟t.Wait()一样 Console.WriteLine($"最终得到的lResult={lResult}"); } Console.WriteLine($"Test结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); }
调整后运行结果如下:
仔细观察结果会发现:
访问Result,主线程会等待Task的完成,阻塞的。
其实async方法在编译后会生成一个状态机(实现了IAsyncStateMachine接口),有兴趣的可以自行去了解下。
至此本文就介绍完了,有兴趣的还可以看下我之前写过一篇也是关于async/await的文章:https://www.cnblogs.com/xyh9039/p/11391507.html
Demo源码:
链接:https://pan.baidu.com/s/1jnG5IpteuKCdmF6-tr--cA 提取码:3onm
此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13622122.html
版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式