找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2352|回复: 12

C#中多线程的那点事-async & await

 火.. [复制链接]
  • 打卡等级:即来则安
  • 打卡总天数:29
  • 打卡月天数:1
  • 打卡总奖励:7791
  • 最近打卡:2025-12-13 17:25:16

2540

主题

1355

回帖

2万

积分

管理员

积分
21304
发表于 2021-4-4 10:29:45 | 显示全部楼层 |阅读模式

大量连接


上一篇《C#中多线程的那点事-Linq & PLinq》,我们讲述了一种全新的集合并行处理的方法PLINQ。PLINQ利用扩展函数,为我们提供了大量常用的集合并行操作函数。从此写代码也变成了一件很愉快的事情。
小明同学很早就来到了教室,用过PLINQ之后,果然回不去了。从他的眼神中,我可以看得出来,小明对我今天的分享很是期待。
今天我们聊一个很酷炫,但是对于有多线程编程经验的人却不太好理解的编程模型:async 和 await。我们在介绍Task的那一篇文章中,就提到Task结合async和await可以非常优雅地写程序。今天我们就来一探究竟吧!
实例演示
我们模拟一个需要异步执行的工作流,其中有3个主要步骤,且下一个步骤,需要依赖上一个步骤的结果:
static Task<int> Func1(int seed){    return Task.Run(() =>    {        Console.WriteLine($"seed: {seed}\t Func1 is Running... ");        Task.Delay(2000).Wait();        return 1 + seed;    });}static Task<int> Func2(int p1){    return Task.Run(() =>    {        Console.WriteLine($"p1:{p1}\t\t Func2 is Running... ");        Task.Delay(2000).Wait();        return 2 + p1;    });}static Task<int> Func3(int p2){    return Task.Run(() =>    {        Console.WriteLine($"p2:{p2}\t\t Func3 is Running... ");        Task.Delay(2000).Wait();        return 3 + p2;    });}
然后我们用常规Task来实现这个工作流的调用过程:
static void WorkFlow(){    var t1 = Func1(100);    var w1 = t1.GetAwaiter();    w1.OnCompleted(() =>    {        var t2 = Func2(w1.GetResult());        var w2 = t2.GetAwaiter();        w2.OnCompleted(() =>        {            var t3 = Func3(w2.GetResult());            t3.Wait();            Console.WriteLine($"Result:{t3.Result}");        });    });}static void Main(string[] args){    Console.WriteLine("Hello async/await World!");    WorkFlow();    Console.ReadKey();}
运行结果如下:

执行结果


从程序来看,没有太特殊的东西。但是有一点,如果这个工作流的步骤增多,我们的WorkFlow这个函数,不太优雅,其中的OnCompleted会越来越深。当然我们可以使用Task的Wait函数,来解决这个问题,但是这样的话WorkFlow这个子函数内部,就会阻塞了:
static void WorkFlow(){    var t1 = Func1(100);    t1.Wait();    var t2 = Func2(t1.Result);    t2.Wait();    var t3 = Func3(t2.Result);    t3.Wait();    Console.WriteLine($"Result:{t3.Result}");}async/await
有没有保持WorkFlow不阻塞的方法呢?
有,就是利用async和await来改写:
static async Task WorkFlow(){    var r1 = await Func1(100);    var r2 = await Func2(r1);    var r3 = await Func3(r2);    Console.WriteLine($"Result:{r3}");}static async Task Main(string[] args){    Console.WriteLine("Hello async/await World!");    await WorkFlow();    Console.ReadKey();}
程序的结果,没有任何改变。但是写法简化了非常多。几乎和我们写串行程序一样了。如果有同学不理解这里一定为什么一定要将WorkFlow写成非阻塞模式的,没关系,在将来某一天,你很可能会遇到这样的场景的。
await 就是 异步等待的意思,await只能用于async修饰的函数内部。async修饰的函数,可以像常规函数一样调用。但是在遇到async函数内部的await关键字之后,相当于该函数就先返回了。待await等待的操作完成之后,又会回到函数中执行await之后的代码。是不是很绕。。。
async修饰的函数,建议返回Task或者Task<T>,而不要返回void。
Main函数,也可以用async修饰,但是建议返回Task。
程序执行流程也比较奇怪,很可能和你预想的执行顺序不同。为了研究程序执行的流程,我加入一些标记性的代码,再来查看运行结果:
static async Task WorkFlow(){    var r1 = await Func1(100);    Console.WriteLine("Func1 end");    var r2 = await Func2(r1);    Console.WriteLine("Func2 end");    var r3 = await Func3(r2);    Console.WriteLine("Func3 end");    Console.WriteLine($"Result:{r3}");}static async Task Main(string[] args){    Console.WriteLine("Hello async/await World!");    await WorkFlow();    Console.WriteLine("WorkFlow end");}
结果如下:

执行流程


我们注意一点,在Main函数中,加入await之后,函数执行的流程和串行执行非常像。
外老师第一次研究这个执行流程的时候,也是一脸懵逼。
感兴趣的同学,一定要动手单步执行这个程序,研究函数执行的流程。
这个过程很难描述清楚,一定要亲自体验,才能发现其奥妙之处。
要是觉得这个流程奇怪的同学,可以去了解一下目前很火的一个概念:协程。虽然我没的查到官方的资料表明async/await就是C#中的协程,但是其用法和功能,都和协程非常像了。这其实是一种全新的编程范式,在处理海量用户并发的时候,经常使用。了解协程之后,理解这种流程就会容易很多。
async/await,或者说Task,是C#中的一种异步编程模型。相比传统的Thread多线程模型,更适合于高并发的场景。使用得当,可以大幅提升程序的并行处理能力。
布置作业
通过调试以上的示例程序,了解async/await的执行流程。也可以自行修改程序,模拟不同的场景。
查询协程相关资料,辅助理解async/await
江湖再见
《C#中多线程的那点事》终于告于段落了!感谢大家的阅读和支持,感谢小明同学的一路陪伴。分享干货知识,咱们下一个专题再见!
来源:外老师

小明同学



工控课堂 www.gkket.com

0

主题

73

回帖

321

积分

注册会员

积分
321
发表于 2021-4-4 10:29:45 | 显示全部楼层
论坛有你更精彩!
工控课堂 www.gkket.com

0

主题

91

回帖

177

积分

新手上路

积分
177
发表于 2021-4-8 04:56:21 | 显示全部楼层
看了楼主的帖子,不由得精神一振,豁然开朗,牛掰
工控课堂 www.gkket.com

0

主题

86

回帖

126

积分

新手上路

积分
126
发表于 2025-11-15 12:55:45 | 显示全部楼层
说得对!狠狠赞同,没毛病~
工控课堂 www.gkket.com

0

主题

81

回帖

125

积分

新手上路

积分
125
发表于 2025-11-15 13:07:38 | 显示全部楼层
原来还有这种操作,长见识了!
工控课堂 www.gkket.com

0

主题

79

回帖

122

积分

新手上路

积分
122
发表于 2025-11-15 13:09:33 | 显示全部楼层
赞同 + 10086,没毛病,完全没毛病
工控课堂 www.gkket.com

0

主题

92

回帖

139

积分

新手上路

积分
139
发表于 2025-11-15 13:14:38 | 显示全部楼层
学到了学到了,这波分享太实用啦!
工控课堂 www.gkket.com

0

主题

101

回帖

160

积分

新手上路

积分
160
发表于 2025-11-15 13:17:00 | 显示全部楼层
谁懂啊!真的被戳中笑点 / 泪点了
工控课堂 www.gkket.com

0

主题

552

回帖

1745

积分

高级会员

积分
1745
发表于 2025-11-15 13:20:37 | 显示全部楼层
路过打卡,为优质内容疯狂打 call
工控课堂 www.gkket.com

0

主题

107

回帖

413

积分

注册会员

积分
413
发表于 2025-11-15 13:23:34 | 显示全部楼层
理性围观,感觉大家说得都有道理
工控课堂 www.gkket.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-23 22:28 , Processed in 0.109472 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表