C# async/awit 嵌套异步 执行顺序 分析

使用非异步方法调用可异步方法(内含嵌套异步)

效果图:

代码(在控制台mian函数中运行该函数):

        private static void AsyncTest()
        {
            Func<Task<string>> Fun1 = () =>
            {
                Thread.Sleep(4000); 
                Console.WriteLine("Fun1 Open");
                return Task.Run(()=>
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("Fun1 Run Open");
                    Console.WriteLine("..............................");
                    Thread.Sleep(5000);
                    Console.WriteLine("..............................");
                    Console.WriteLine("Fun1 Run Close");
                    return "Fun1";
                }); 
            }; 
            Func<Task<string>> Fun2 = async () =>
            {
                Thread.Sleep(1000); 
                Console.WriteLine("Fun2 Open"); 

                var str2 = await Fun1(); 
                Thread.Sleep(1000);
                Console.WriteLine("Fun1 Result "+ str2);

                Console.WriteLine("Fun2 Close"); 
                return "Fun2";
            };
            
            Console.WriteLine("Asyn Open"); 
            var str = Fun2();
            Console.WriteLine("Fun2 Result " + str); 
            Console.WriteLine("Asyn Close");
        }

情景:

  1. 两个异步程序Fun2/Fun1
  2. Fun2使用(await)调用Fun1
  3. Fun2不使用异步调用

分析:

  1. 主线程执行过程中,遇到异步Fun2,执行同步过程,进入函数Fun2
  2. 函数Fun2执行过程中,遇到异步Fun1,执行异步过程await,进入Fun1
  3. 函数Fun1执行过程中,遇到异步时间Run,开启异步
  4. 主函数不等待异步,Fun1无返回值,输出Task对象
  5. 函数Fun2等待Fun1结果,再执行await后的语句

结论:

  1. 封装后的异步调用,如果被同步调用,应该使用void/Task无返回值方式
  2. await后的语句,相当于异步调用后的回调方法,写法更美观

使用await调用异步方法(嵌套异步)

代码:

var str = await Fun2();

在上文代码中Fun2函数前面加上await

效果图:


分析:

  1. 主线程执行过程中,遇到异步Fun2,执行异步过程await,进入函数Fun2
  2. 函数Fun2执行过程中,遇到异步Fun1,执行异步过程await,进入Fun1
  3. 函数Fun1执行过程中,遇到异步时间Run,开启异步
  4. 函数Fun2等待Fun1结果,再执行await后的语句
  5. 主函数等待Fun2结果,再执行await后的语句

结论:

  1. 要想达到嵌套异步的回调效果,每一个异步环节都要使用await标记分割

使用await调用异步方法(连续await)

效果图


代码:

Fun1添加参数p做区分,Fun2添加并行的await

            Func<string, Task<string>> Fun1 = (string p) =>
            {
                Thread.Sleep(4000); 
                Console.WriteLine("Fun1 Open " + p);
                return Task.Run(()=>
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("Fun1 Run Open " + p);
                    Console.WriteLine("..............................");
                    Thread.Sleep(5000);
                    Console.WriteLine("..............................");
                    Console.WriteLine("Fun1 Run Close " + p);
                    return "Fun1 " + p;
                }); 
            }; 
            Func<Task<string>> Fun2 = async () =>
            {
                Thread.Sleep(1000); 
                Console.WriteLine("Fun2 Open"); 

                var str2 = await Fun1("No.1"); 
                Thread.Sleep(1000);
                Console.WriteLine("Fun1 Result "+ str2);

                str2 = await Fun1("No.2");
                Thread.Sleep(1000);
                Console.WriteLine("Fun1 Result " + str2);

                Console.WriteLine("Fun2 Close"); 
                return "Fun2";
            };

结论:

  1. 多个await并不会破坏await的“异步回调模式”
  2. 在上一个await执行回调后,下一个await作为回调函数内的语句继续执行await的过程
  3. 该语法糖很好吃,很强大的语法,拯救了键盘。

注意:

await异步回调的边界,是async所标记的函数的边界。其async函数内部的循环/判断等语句,都要服从与await的等待与回调过程。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值