如题。
这部分花了很久才搞明白。网上压根没查到正经八百的理解,坑啊!
这两个关键字,往简单说,译为“异步”和“等待”。按这个理解,恭喜你,掉坑里了,估计很久爬不出来。
其实关键在async。在语法上,它应该理解为:(由async修饰的方法,下面简称“S”)包含异步内容。注意:是“包含”,而不是方法里的所有内容都异步执行。既然包含异步内容,在执行的时候,就一定会遇到多线程的代码。这种情况,要么是调用别人的方法里有多线程,要么你自己用类似Task.Run的东西运行多线程。反正必须有。没有,它就跟单线程(同步方法)是一样的了。
为了方便调用S的时候,让它的异步部分单独跑,程序闷头干自己的活,S的返回类型通常都是Task或Task<result>。有关Task的知识自己补,也可以看我博客的相关文章。
这样就可以用类似“Task t=S();/*自己该干嘛干嘛*/;await t;”的方式实现程序并行。不需要并行?“await S();”就行。
常见问题1:async A里有async B,B里新开了个线程。Main在调用A的时候,新开了几个线程?答:1个,就是B里那个。A和B里的其他代码,都是同步方式执行的。
常见问题2:我有一段同步代码X,我希望把它写成异步方法A,方便异步执行。直接async A{x},行不?答:不行!必须形如:B{x},async Task A{await Task.Run(B);}。你不开新线程,就算查了一堆资料,写出来“return Task.CompletedTask;”,它也还是只能同步执行。原因很简单:没多线程,你上哪异步去?指望一个async就多线程了?你想多了。
可以观察以下代码的运行结果,体会上述内容。环境:VS2022,.NET6
Console.WriteLine("我开始上班"); var 领导 = Test.领导上班(); Console.WriteLine("我努力工作"); await 领导; Console.WriteLine("我下班"); class Test { public static async Task 领导上班() { var w=new 划水(); Console.WriteLine("早上划水,影响大家干活"); w.开划(); Console.WriteLine("中午划水,不耽误大家加班"); var t = Task.Run(w.开划); await t; } } class 划水 { public int MyTime { get; set; } = 3000; public void 开划() { Thread.Sleep(MyTime); Console.WriteLine("划水完毕"); } }
运行结果:
可以看到,“我工作”是在领导早上划水之后,中午正式划水之前。我工作的时候,领导中午也正在划水。即真正异步的,还是那个Task.Run。