C#异步编程看这篇就够了

随着.NET Core的流行,相信你现在的代码中或多或少的会用到async以及await吧!毕竟已成标配。那么我们为什么要用async以及await呢?其实这是微软团队为我们提供的一个语法糖,让我们不用996就可以轻松的编写异步代码,并无太过神奇的地方。那么,问题来了,什么是异步?异步到底又是怎样的一个过程呢?

从一个故事说起

在开始讲异步前我们先从一个生活中的小故事说起吧。话说2019年12月15日周日这一天有位程序猿小祝在这天居然没有加班,选择在家休息了,然后他习惯性的用Microsoft To Do罗列了一下这天要做的事情,如下图所示:

这一天这个程序猿小祝计划早上九点起床洗澡,然后吃早餐,洗衣服,分享一篇关于C#异步相关的文章,晚上在家加下班~~没错,这个苦逼休息的时候也得工作,不然下周的任务有可能完不成要挨批了。

这个时候这个程序猿小祝可以选择,1.起床洗澡,2.吃早餐,3.洗衣服,4.写文章,5.打会球然后“远程写代码”。这个过程有严格的执行顺序,这个过程可以视为一个同步的过程。如下图所示:

当然,这个程序猿小祝却采用了另一种方式来进行:起床后先把衣服换下来用洗衣机洗了,然后开始洗澡,然后吃饭,写了一会文章,然后等衣服洗好后再把衣服给晾好继续回来写文章,最后在晚上的时候远程写代码。在这个过程中这个程序猿在洗衣服的同时就去洗澡,吃饭写了会文章了,这个过程就是一个异步的过程。

可能这个故事比喻的不恰当,不过大伙将就着看下吧,总结一下同步跟异步吧:

  1. 同步方法:可以认为程序是按照你写这些代码时所采用的顺序执行相关的指令的。

  2. 异步方法:可以在尚未完成所有指令的时候提前返回(如上面的洗衣服过程没执行完就返回去洗澡了),等到该方法等候的那项任务执行完毕后,在令这个方法从早前还没执行完的那个地方继续往下运行(如:衣服洗好晾好后,继续写文章了)。

下面我们结合伪代码来进行更加详细的讲解吧。

伪代码实例讲解

这一节我们就用伪代码来分别实现下同步过程及异步过程吧。

同步过程

下面我们用伪代码来实现上述故事中的过程吧。

static void Main(string[] args){Console.WriteLine("Main异步演示开始~~~~~");Stopwatch stopwatch = Stopwatch.StartNew();Bash();//洗澡BreakFast();//吃早餐WashClothes();//洗衣服WriteArticle();//写文章WritingCode();//写代码Console.WriteLine("Main异步演示结束~~~~~共用时{0}秒!", stopwatch.ElapsedMilliseconds/1000);Console.ReadKey();}private static void Bash(){Console.WriteLine("洗澡开始~~~~~");Thread.Sleep(1*1000);//模拟过程Console.WriteLine("洗澡结束~~~~~");}private static void BreakFast(){Console.WriteLine("吃早餐开始~~~~~");Thread.Sleep(1 * 1000);//模拟过程Console.WriteLine("吃早餐结束~~~~~");}private static void WashClothes(){Console.WriteLine("洗衣服开始~~~~~");Thread.Sleep(6 * 1000);//模拟过程Console.WriteLine("洗衣服结束~~~~~");}private static void WriteArticle(){Console.WriteLine("写文章开始~~~~~");Thread.Sleep(20 * 1000);//模拟过程Console.WriteLine("写文章结束~~~~~");}private static void WritingCode(){Console.WriteLine("写代码开始~~~~~");Thread.Sleep(12 * 1000);//模拟过程Console.WriteLine("写代码结束~~~~~");}

上面的代码没什么难的,写完代码后我们直接dotnet run一下代码,如下图所示:

我们可以看到这个代码的执行过程是严格按照我们编码的顺序执行的,即同步运行的代码。这里用时共40秒!

异步过程

我们只需要稍微改造下使得代码异步执行再来看下效果吧!伪代码如下:

static async Task Main(string[] args){Console.WriteLine("Main异步演示开始~~~~~");Stopwatch stopwatch = Stopwatch.StartNew();List<Task> tasks = new List<Task>{Bash(),//洗澡};tasks.Add(BreakFast());//吃早餐tasks.Add(WashClothes());//洗衣服tasks.Add(WriteArticle());//写文章tasks.Add(WritingCode());//写代码await Task.WhenAll(tasks);Console.WriteLine("Main异步演示结束~~~~~共用时{0}秒!", stopwatch.ElapsedMilliseconds/1000);Console.ReadKey();}private static async Task Bash(){Console.WriteLine("洗澡开始~~~~~");await Task.Delay(1*1000);//模拟过程Console.WriteLine("洗澡结束~~~~~");}private static async Task BreakFast(){Console.WriteLine("吃早餐开始~~~~~");await Task.Delay(1 * 1000);//模拟过程Console.WriteLine("吃早餐结束~~~~~");}private static async Task WashClothes(){Console.WriteLine("洗衣服开始~~~~~");await Task.Delay(6 * 1000);//模拟过程Console.WriteLine("洗衣服结束~~~~~");}private static async Task WriteArticle(){Console.WriteLine("写文章开始~~~~~");await Task.Delay(20 * 1000);//模拟过程Console.WriteLine("写文章结束~~~~~");}private static async Task WritingCode(){Console.WriteLine("写代码开始~~~~~");await Task.Delay(12 * 1000);//模拟过程Console.WriteLine("写代码结束~~~~~");}

然后我们再直接dotnet run一下代码,如下图所示:

我们可以看到这个代码的执行过程中遇到await后就会返回执行了,待await的代码执行完毕后才继续执行接下来的代码的!为了避免有的读者看不懂,我简单分析其中一个方法的执行过程吧。具体的还需要你自己把异步代码拷贝下来,多打几个断点,然后把等待时间*100(时间长点方便我们查看断点的进入顺序,否则时间短,还没来得及进断点可能代码已经执行完了)看看断点的进入步骤吧!

我也只列了一部分,具体的你们自行打断点看下吧。

异步原理解析

通过上面的伪代码分析相信你已经对异步有所了解了。接下来我们就来看看系统到底是怎么实现出这样的效果的。下面只是简单地进行下表述,如果不正确的欢迎大家指正。

编译器在处理异步方法的时候,会构建一种机制,该机制可以启动await 语句所要等候的那项异步任务,并使得程序在该工作完成之后,能够用某个线程继续执行await语句后面的那些代码。这个await语句正是关键所在。编译器会构建相应的数据结构,并把await之后的指令表示成delegate,使得程序在处理完那项异步任务之后,能够继续执行下面的那些指令。编译器会把当前方法中的每一个局部变量的值都保存在这个数据结构中,并根据await语句所要等候的任务来配置相应的逻辑,让程序能够在该任务完成之后指派某个线程,从await语句的下一条指令开始继续执行。实际上,这相当于编译器生成了一个delegate,用以表示await语句之后的那些代码,并写入了相应的状态信息,用以确保await语句所等候的那项任务执行完毕以后这个delegate能够正确的得到调用。

这使得该方法看上去好像是从早前暂停的地方继续往下执行了,也就是说,系统会把状态恢复到早前暂停的样式,并且直接把程序中的某个线程放到适当的语句上,令其能够继续向下运行。

这个过程实际上是由SynchronizationContext类来实现的,该类用来保证异步方法能够在它所等候的任务执行完毕时,从早前停下来的地方继续往下运行,并确保该方法此时所处的环境与上下文能够与当初的情况一样。

总结

通过上面的讲述我们可以知道通过asyncawait关键字写出来的异步方法并没有太过神奇的地方。只不过编译器会针对这种方法生成许多代码,使得调用这个方法的主调方无需等待该方法完工,就可以继续往下执行,并确保该方法所等候的那项任务在执行过程中发生的错误能够适当的得到回报。这样的好处是,如果异步方法执行到await语句时它所要等候的那项任务还没有完成,那么该方法的执行进度就会暂停在那里,直到那项任务完成之后,才会继续往下执行。

希望这篇文章对你有所帮助,当然光了解异步没用,还要能够高效的编写异步代码才行哦,接下来我会抽时间讲讲进行异步开发的一些建议。当然我以前也写过相关的文章,你可以提前看下。同时欢迎大家加入.net core两千人交流群637326624`交流。当然我不会告诉你,关注公众号会第一时间收到文章推送。

很久没写文章了,生疏了很多,大家将就着看吧!

参考

《More Effective C#》机械工业出版社

依乐祝自己的理解

好看你就点点我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2019 AI Bootcamp·Guangzhou 参会日记

2019年的全球AI训练营在北京、上海、广州、杭州、宁波五个地方同时举办&#xff01;12月14日&#xff0c;微软全球AI Bootcamp活动再次驾临广州&#xff0c;本次会议结合 ML.NET 和基于 SciSharp 社区介绍最新的基于 .NET Core 人工智能技术&#xff0c;还有云端人工智能解决方…

AI Boot Camp 分享之 ML.NET 机器学习指南

今天在中国七城联动&#xff0c;全球134场的AI BootCamp胜利落幕&#xff0c;广州由卢建晖老师组织&#xff0c;我参与分享了一个主题《ML.NET 机器学习指南和Azure Kinect .NET SDK概要》&#xff0c;活动虽然只有短短的2天时间的宣传&#xff0c;报名70人&#xff0c;到场40多…

使用 Ocelot 匹配路由的方法匹配路由

使用 Ocelot 匹配路由的方法匹配路由Intro之前我们在 Ocelot 网关的基础上自定义了一个认证授权的 Ocelot 中间件&#xff0c;根据请求的路径和 Method 进行匹配&#xff0c;找到对应的权限配置&#xff0c;并判断是否可以拥有访问资源的角色&#xff0c;如果没有则返回 401/40…

【.NET Core 3.1】 策略授权中获取权限数据

▼更多精彩推荐&#xff0c;上午11点到达▼随着项目关注度渐渐升高&#xff0c;目前已经1.2k个star&#xff0c;我的内心反而更加的惶恐了起来&#xff0c;最近也是很有强迫症&#xff0c;只要有小伙伴反馈项目的问题&#xff0c;就很着急&#xff0c;哪怕一丁点的问题&#xf…

《Dotnet9》系列-开源C# Winform控件库1《HZHControls》强力推荐

大家好&#xff0c;我是Dotnet9小编&#xff0c;一个从事dotnet开发8年的程序员。我最近在写dotnet分享文章&#xff0c;希望能让更多人看到dotnet的发展&#xff0c;了解更多dotnet技术&#xff0c;帮助dotnet程序员应用dotnet技术更好的运用于工作和学习中去。文章阅读导航一…

不要叫我,我会叫你

之前看过前辈Artech关于控制反转的一篇文章&#xff0c;文章通俗易懂且言语精炼&#xff0c;写技术文章既是积累也是分享&#xff0c;既然是分享那么必须让读者能够明白到底讲解的什么&#xff0c;所以在这里我也挑战下自己&#xff0c;看看能不能将概念通过简洁代码和语言的形…

用.NET模拟天体运动

用.NET模拟天体运动这将是一篇罕见而偏极客的文章。我上大学时就见过一些模拟太阳系等天体运动的软件和网站&#xff0c;觉得非常酷炫&#xff0c;比如这个&#xff08;http://www.astronoo.com/en/articles/positions-of-the-planets.html&#xff09;&#xff1a; 其酷炫之处…

01 手把手带你构建大规模分布式服务--高并发、高可用架构系列,高质量原创好文!...

作者&#xff1a;丁浪&#xff0c;目前在创业公司担任高级技术架构师。曾就职于阿里巴巴大文娱和蚂蚁金服。具有丰富的稳定性保障&#xff0c;全链路性能优化的经验。架构师社区特邀嘉宾&#xff01;阅读本&#xff08;系列&#xff09;文章&#xff0c;你将会收获&#xff1a;…

如何正确的探索 Microsoft Ignite The Tour

Microsoft Ignite The Tour 是一年一度微软为全球开发者、IT专家、安全专家以及数据专家提供的为期两天&#xff0c;包含众多核心产品的实践性技术培训。2019.12.10-2019.12.11 已经在北京国家会议中心胜利闭幕&#xff0c;我作为一名Speaker 参与了两门课程的分享&#xff0c;…

回顾这一年,我沉默良久

今天是一个特殊的日子&#xff0c;因为还有一周就2024了。 回忆 我骑着我心爱的小电驴慢悠悠的走在下班的路上&#xff0c;看着万家灯火&#xff0c;匆匆而过的行人和那开着三轮车的摊贩们与城管斗智斗勇。 我陷入了回忆&#xff1f; 回忆着今年的进程&#xff0c;先是裁员…

使用ASP.NET Core 3.x 构建 RESTful API - 4.1 面向外部的Model

Entity Framework Core 使用的 Entity Model 是用来表示数据库里面的记录的。 而面向外部的 model 则表示了要传输的东西。这类 model 有时候叫做 Dto&#xff0c;有时候叫做 ViewModel。 举一个例子&#xff0c;人员的Entity Model如下&#xff1a; 最后一个字段表示人员的出生…

特意向大家推荐.NET技术圈一些优秀开发者的公众号

在互联网技术飞速发展的今天&#xff0c;各种技术席卷而来&#xff0c;总是让人感觉压力山大。作为.NET开发者&#xff0c;我们该如何刷新自己&#xff0c;实现价值的提升呢&#xff1f;2019年.NET中国开发者峰会之后&#xff0c;我们汇总了.NET技术圈一些优秀开发者的公众号&a…

ASP.NET Core on K8S深入学习(11)K8S网络知多少

Photo &#xff1a;Kubernetes文 | Edison Zhou本文已加入《.NET Core on K8S 学习与实践系列文章索引目录》&#xff0c;点击查看阅读更多容器化相关文章&#xff0c;希望对你有所帮助&#xff01;Kubernetes网络模型我们都知道Kubernetes作为容器编排引擎&#xff0c;它有一个…

Amazon、Linux基金会开发边缘网络交换器操作系统

Amazon、Linux基金会和5家网络业者上周宣布边缘网络交换器操作系统项目DENT&#xff0c;可能冲击开发专属操作系统的网络晶片及设备业者。DENT希望集结网络设备制造商&#xff0c;系统整合商及晶片厂商&#xff0c;为分散式厂区、远端办公室、分公司及零售业开发解构式网络交换…

多库操作:多个数据库的动态切换(一)

▼更多精彩推荐&#xff0c;上午11点到达▼在平时的开发中&#xff0c;受到传统模式的影响&#xff0c;我们都是习惯了单一的数据库表操作&#xff0c;把数据都建到一个库里边&#xff0c;然后进行增删改查&#xff0c;这个是很经典的开发模式。但是随着项目开发&#xff0c;总…

超燃| 2019 中国.NET 开发者峰会视频发布

首届 .NET Conf China 2019 年&#xff0c;注定会是 .NET Core 社区发展的关键一年&#xff0c;诸多重大事件在这一年发生&#xff01;正如大家所期待的那样&#xff0c;刷新中国 .NET 社区的年度盛会——2019 中国 .NET 开发者峰会&#xff08;.NET Conf China 2019&#xff0…

Lingo优化模型概述

注意事项 lingo中变量默认是非负的示例 model: max 2*x1 3*x2; 2*x1 x2 < 8; 4*x1 3*x2 < 15; end数组型变量 集合段、数据段、目标与约束段、计算段、初始段和子模型段 model: sets: s/1..10/:x; endsetsdata: x 1 2 3 4 5 6 7 8 9 10; enddatamin sum(s(i):x…

刷新.NET

.NET Core 发布的那一天起&#xff0c;它在完成自我刷新的过程&#xff0c;一切为了适应未来&#xff0c;云原生。不仅仅跨平台那么简单。.NET Core 未来发展路线我们发现跳过了.NET Core 4.X 避免了和目前.NET Framework4.X命名上的混乱&#xff0c;明年直接命名为了.NET 5 &a…

如何备份和还原您的Kubernetes集群资源和持久卷?

众所周知&#xff0c;Kubernetes可以协调连接在一起&#xff0c;作为一个工作单元&#xff0c;形成高可用性的计算机集群。Kubernetes包含许多抽象概念&#xff0c;这些抽象概念允许将容器化的应用程序部署到集群中&#xff0c;而无需将它们附加到单独的机器上。简而言之&#…

sklearn评价指标

机器学习中&#xff0c;常见的评价指标如下&#xff1a; 准确率&#xff08;Accuracy&#xff09; 精确率&#xff08;Precision&#xff09; 灵敏度&#xff08;Sensitivity&#xff09;&#xff0c;即召回率&#xff08;Recall&#xff09; 特异度&#xff08;Specificity&am…