c# hdf5 写string_C#中多线程的那点事-async & await

f645bfaa454eeded598e545e9aab8cd7.png

大量连接

上一篇《C#中多线程的那点事-Linq & PLinq》,我们讲述了一种全新的集合并行处理的方法PLINQ。PLINQ利用扩展函数,为我们提供了大量常用的集合并行操作函数。从此写代码也变成了一件很愉快的事情。

小明同学很早就来到了教室,用过PLINQ之后,果然回不去了。从他的眼神中,我可以看得出来,小明对我今天的分享很是期待。

今天我们聊一个很酷炫,但是对于有多线程编程经验的人却不太好理解的编程模型:async 和 await。我们在介绍Task的那一篇文章中,就提到Task结合async和await可以非常优雅地写程序。今天我们就来一探究竟吧!

实例演示

我们模拟一个需要异步执行的工作流,其中有3个主要步骤,且下一个步骤,需要依赖上一个步骤的结果:

static Task Func1(int seed){    return Task.Run(() =>    {        Console.WriteLine($"seed: {seed} Func1 is Running... ");        Task.Delay(2000).Wait();        return 1 + seed;    });}static Task Func2(int p1){    return Task.Run(() =>    {        Console.WriteLine($"p1:{p1} Func2 is Running... ");        Task.Delay(2000).Wait();        return 2 + p1;    });}static Task Func3(int p2){    return Task.Run(() =>    {        Console.WriteLine($"p2:{p2} 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();}

运行结果如下:

8f51661ab544106e4251c3a62ea297c6.png

执行结果

从程序来看,没有太特殊的东西。但是有一点,如果这个工作流的步骤增多,我们的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 void WorkFlow(){    var r1 = await Func1(100);    var r2 = await Func2(r1);    var r3 = await Func3(r2);    Console.WriteLine($"Result:{r3}");}static void Main(string[] args){    Console.WriteLine("Hello async/await World!");    WorkFlow();    Console.ReadKey();}

程序的结果,没有任何改变。但是写法简化了非常多。几乎和我们写串行程序一样了。如果有同学不理解这里一定为什么一定要将WorkFlow写成非阻塞模式的,没关系,在将来某一天,你很可能会遇到这样的场景的。

await 就是 异步等待的意思,await只能用于async修饰的函数内部。async修饰的函数,可以像常规函数一样调用。但是在遇到async函数内部的await关键字之后,相当于该函数就先返回了。待await等待的操作完成之后,又会回到函数中执行await之后的代码。是不是很绕。。。

此处应该有流程图

程序执行流程也比较奇怪,很可能和你预想的执行顺序不同。为了研究程序执行的流程,我加入一些标记性的代码,再来查看运行结果:

static async void 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 void Main(string[] args){    Console.WriteLine("Hello async/await World!");    WorkFlow();    Console.WriteLine("WorkFlow end");    Console.ReadKey();}

结果如下:

5feb591a9b064bd80a4143c1b059164b.png

执行流程

我们注意一点,WorkFlow这个函数,在Fun1执行结束之前(第一个await后),就已经返回了,其后的代码就开始执行了。这也是为什么要在最后面加上【Console.ReadKey();】的原因,这是为了阻止程序即出。

外老师第一次研究这个执行流程的时候,也是一脸懵逼。

感兴趣的同学,一定要动手单步执行这个程序,研究函数执行的流程。

这个过程很难描述清楚,一定要亲自体验,才能发现其奥妙之处。

要是觉得这个流程奇怪的同学,可以去了解一下目前很火的一个概念:协程。虽然我没的查到官方的资料表明async/await就是C#中的协程,但是其用法和功能,都和协程非常像了。这其实是一种全新的编程范式,在处理海量用户并发的时候,经常使用。了解协程之后,理解这种流程就会容易很多。

布置作业

通过调试以上的示例程序,了解async/await的执行流程。也可以自行修改程序,模拟不同的场景。

查询协程相关资料,辅助理解async/await

江湖再见

《C#中多线程的那点事》终于告于段落了!感谢大家的阅读和支持,感谢小明同学的一路陪伴。分享干货知识,咱们下一个专题再见!

0c51ae165db1f8a503dec706a0398795.gif

小明同学

系列文章

下面是给同学们准备的干货:

《C#中多线程的那点事儿-Thread入门》

《C#中多线程的那点事-多线程的代价》

《C#中多线程的那点事-线程池》

《C#中多线程的那点事-锁》

《C#中多线程的那点事-死锁》

《C#中多线程的那点事-Task再次起航》

《C#中多线程的那点事-Parallel》

《C#中多线程的那点事-Linq & PLinq》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值