AI智能
改变未来

C# async/await异步编程

最近在看关于基于c#的异步编程,看了很多网上的资料和B站上的视频,个人总结(纯个人理解,如有歧义,请指出):所谓的异步编程就是多线程的编程。我们知道一个程序运行时,会在计算机上开始一个进程,每个进程是相互独立的,所使用的计算机资源也是独立的,而一个进程底下又有着若干个线程,这些进程里的线程公用进程的所有资源,而每个线程间又是独立的(原子性),因为原子性的关系,我们有了所谓的异步操作。

什么又叫异步操作呢?简单的说就是,两个人同时在厨房炒菜(厨房为进程,人为线程,假设一个叫“王杀猪”,一个叫“赵杀牛”),厨房里有一个炒菜的锅、两把刀、两个案板(这些为进程里的资源),两个人共用着这些资源,而王杀猪做杀猪的事,赵杀牛做杀牛的事,两个人同时进行各自的事的时候(比如甲在切猪肉,乙在切牛肉),这时候就可以称之为–异步操作(编程)。同步操作(编程)同理,厨房里只有一个炒菜的锅,不可能同时炒猪肉和炒牛肉,那王杀猪和赵杀牛之间就只能一个人等另外一个人炒完后才能接着做,这就是所谓的同步操作。本篇只赘述异步操作。

微软在.Net FrameWork4.5后引入了强大异步操作关键字 — async/await。使用这两个关键字,使得我们的异步编程变得更简单,代码可读性变得更强,本章就针对这两个关键字进行举例示范,而对于异步编程来说,还有许多的方法去实现(线程、线程池等等),在本章就不做赘述,感兴趣者可以到网上去搜索相关内容。

新建一个控制台程序,取名叫 TestAsync :

[code]using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Threading;namespace TestAsync{class Program{static void Main(string[] args){Console.WriteLine(\"我是一个厨房\");Console.ReadKey();}}}

接下来我们创建两个无返回值的方法,一个取名为WangKillPig(),另一个取名为ZhaoKillBull():

我们先看不使用异步操作的时候:

[code]using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Threading;namespace TestAsync{class Program{static void Main(string[] args){WangKillPig();ZhaoKillBull();Thread.Sleep(5000);Console.WriteLine(\"我是一个厨房\");Console.ReadKey();}static void WangKillPig(){Thread.Sleep(5000);Console.WriteLine(\"猪肉切好了\");}static void ZhaoKillBull(){Thread.Sleep(5000);Console.WriteLine(\"牛肉切好了\");}}}

假设切猪肉和切牛肉用的时间都是5秒,采用同步操作的时候,F5运行程序,我们会先看到控制台先打印了“猪肉切好了”

然后过了大概5秒再打印出“牛肉切好了”

然后再过了大概5秒再打印出“我是一个厨房”

这就是同步编程,以上三个操作均执行在主线程上,所以他们在时间轴上有一个串行的关系,他们之间有一个先后的执行顺序。

现在看异步操作:

[code]namespace TestAsync{class Program{static void Main(string[] args){WangKillPig();ZhaoKillBull();Thread.Sleep(5000);Console.WriteLine(\"我是一个厨房\");Console.ReadKey();}static async void WangKillPig(){await Task.Run(() =>{Thread.Sleep(5000);Console.WriteLine(\"猪肉切好了\");});}static async void ZhaoKillBull(){await Task.Run(() =>{Thread.Sleep(5000);Console.WriteLine(\"牛肉切好了\");});}}}

我们可以看到使用了 async/await 关键字

WangKillPig()方法里面使用了Task,熟悉的人应该知道,Task实现了关于线程池等相关的一些巴拉巴拉的接口,按本人的理解也是创建了一条新的线程执行任务(实际上也是如此,程序运行的时候,打断点单步执行可以看到有新的“工作线程”被创建)。async声明了WangKillPig()是一个异步方法,配对的await后面跟着一个要执行的异步操作,Run()里面为一个匿名方法(Action委托),这个方法执行切猪肉的任务(如果不了解匿名方法或者委托,可以先自行搜索相关内容)。ZhaoKillBull()同理。

此时我们F5运行程序,得到的结果:

程序运行后,过了5秒,三条数据同时显示,这个顺序看起来不错,刚好跟MAIN()方法里的顺序一样,实际上博主也是刚好走了狗屎运执行的时候碰巧得到了这个数据,实际上,如果这个程序多执行几遍就可以看出,每次执行得到的结果是不一样的,也就是说这三条数据的显示顺序是不确定的,这就是我们所说的异步操作了,如何理解呢:三条数据实际上执行在了三个不同的线程上,此时,就有了三个不同的时间轴,三条数据在各自的时间轴上做自己的事,互不影响,他们的执行都是5秒钟结束,所以我们就能看到程序运行后5秒他们三个同时显示,而为什么顺序上是不确定的,那就是因为三条数据在各自的时间轴上的执行速度还是会有略微一丢丢的差距的,这些差距是毫秒级别的,近乎于相等。

如果你觉得这样不爽,看不出异步操作时线程同时执行的效果,那你自己可以修改线程的休眠时间就可以看出来了,假设把 Console.WriteLine(\”我是一个厨房\”) 这一句上面的 Thread.Sleep(5000) 去掉,你会发现程序运行时,打印的结果永远是先打印“我是一个厨房”,再打印切猪肉和切牛肉。

扩展1:Task<IResult>里面为一个泛型,我们上面的事例中仅仅展示了无返回的方法,如果想定义一个有返回的异步方法,可以写成:async Task<–(任意参数,可以为int、string或者实体)–> XXX()(例如:asyn Task<string> MyMethon()),然后再Task.Run里面调用要实现的方法就可以了(注意调用的方法返回的参数要与Task<参数类型>中的参数类型相同)。

扩展2:await后面的方法执行结束后还能继续写一些代码,这些代码会在await里的方法执行结束后再接着往下继续执行。

以上为C# async/await异步编程,以上代码内容为本人自行编写的测试代码,内容为本人自己撰写,如有雷同,万分荣幸,感谢在评论区指出不同的意见和建议。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » C# async/await异步编程