理解C#里的async和await

如题。

这部分花了很久才搞明白。网上压根没查到正经八百的理解,坑啊!

这两个关键字,往简单说,译为“异步”和“等待”。按这个理解,恭喜你,掉坑里了,估计很久爬不出来。

其实关键在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("划水完毕");
    }
}

运行结果:

理解C#里的async和await

 

 可以看到,“我工作”是在领导早上划水之后,中午正式划水之前。我工作的时候,领导中午也正在划水。即真正异步的,还是那个Task.Run。

 

上一篇:异步IO:async/await


下一篇:promise与aysnc/await 解析