首页 > await使用中的阻塞和并发(一)

await使用中的阻塞和并发(一)

好吧,不加点陈述不让发首页。那我们来陈述一下本篇提到的问题和对应的方法。

在.NET4.5中,我们可以配合使用async和await两个关键字,来以写同步代码的方式,实现异步的操作。

好处我目前看来有两点:

1.不会阻塞UI线程。一旦UI线程不能及时响应,会极大的影响用户体验,这点在手机和平板的APP上尤为重要。

2.代码简洁。

  • 相对基于event的异步方式,在多次回调的情况下(比如需要多次调web service,且后续调用基于前次调用的结果)特别明显。可以将多个+=Completed方法合并到一起。
  • 相对于Begin/End的异步方式,避免了N重且不能对齐的大括号。

     

在同一个方法里存在多个await的情况下,如后续Async方法无需等待之前的Aysnc方法返回的结果,会隐式的以并行方式来运行后面的Async方法。

值得注意的是错误的写法会导致非预期的阻塞,下文会以简单的例子来讨论在使用await的情况下,怎样实现多个Task的并发执行。

我们这里先看几个方法定义:

复制代码
        static async Task Delay3000Async(){await Task.Delay(3000);Console.WriteLine(3000);Console.WriteLine(DateTime.Now);}static async Task Delay2000Async(){await Task.Delay(2000);Console.WriteLine(2000);Console.WriteLine(DateTime.Now);}static async Task Delay1000Async(){await Task.Delay(1000);Console.WriteLine(1000);Console.WriteLine(DateTime.Now);}
复制代码

作用很简单,仅仅是起到延迟的作用。我们再来看如下写法的调用

复制代码
            Console.WriteLine(DateTime.Now);new Action(async () =>{await Delay3000Async();await Delay2000Async();await Delay1000Async();})();        
复制代码

结果如图,可以看出3个await是线性执行,第一个await会返回并阻止接下来的await后面的方法。这应该不是我们想要的效果,毕竟后面的方法并不依赖第一个方法的执行。

我们换一种写法,再运行一次程序:

复制代码
            var task3 = Delay3000Async();var task2 = Delay2000Async();var task1 = Delay1000Async();new Action(async () =>{await task3;await task2;await task1;})();    
复制代码

可以看到3个await后面的方法是并行执行的。MSDN的解释如下:

In an async method, tasks are started when they’re created. The Await (Visual Basic) or await (C#) operator is applied to the task at the point in the method where processing can’t continue until the task finishes. 

However, you can separate creating the task from awaiting the task if your program has other work to accomplish that doesn’t depend on the completion of the task.

Between starting a task and awaiting it, you can start other tasks. The additional tasks implicitly run in parallel, but no additional threads are created.

MSDN原文传送门

到这里并没有结束 ,后面还有一些奇怪的事情:

复制代码
            var tasks = new List{Delay3000Async(),Delay2000Async(),Delay1000Async()};tasks.ForEach(async _ => await _);
复制代码

这个结果和上面是一样的,可以并行执行。这并不奇怪,我们仅仅是把Task放到一个List里,按照MSDN的说法,Task在被我们放进List时就被创建,且并发执行了。

那么我们再来一个List,这回放进去的不是Task,而是Func:

复制代码
            var funcList = new List>(){Delay3000Async,Delay2000Async,Delay1000Async};funcList.ForEach(async _ => await _());
复制代码

仍然可以并发执行,看上去似乎没什么问题,但是作为Func来存储到List里,应该是没有被创建出来才对。为什么会能够并发呢?

我们再来看最后一组写法:

复制代码
            Func func3 = Delay3000Async;Func func2 = Delay2000Async;Func func1 = Delay1000Async;new Action(async () =>{await func3();await func2();await func1();})();
复制代码

意料之中的,以上的写法并不能够做到并发执行。而是需要按顺序执行func3,func2和func1。这很好解释,因为: a task is awaited as soon as it’s created。我们在创建Task之后立即就要求阻塞并等待完成才进行下一步。

写到这里的时候对List>的例子开始迷糊了。参考了Reflector反编译的结果……我想说……没看出来有什么区别……本篇先到这里。一旦琢磨出个所以然,我再发第二篇好了。

还恭请各位高人不吝赐教,多多提点。

 

补充:对List>的那个例子,我怀疑是Foreach这个扩展方法在偷偷做了优化。故增加了如下的试验:

复制代码
       static async Task TestForeach(){var funcList = new List>(){Delay3000Async,Delay2000Async,Delay1000Async};foreach (var item in funcList){ 

          //这里干了件蠢事,不要主动阻塞在这里,就可以并发了……await item();}}
复制代码

试验结果表明用foreach来写的话,确实是做不到并行执行的。那么就需要去看一下Foreach的背后到底发生了什么。我还要研究研究才能写下一篇……

 哈哈哈哈,干了件蠢事情……

转载于:https://www.cnblogs.com/leo9527/p/10340699.html

更多相关:

  • 文章目录描述函数成员及使用总结 我们上一篇描述关于C++多线程中的异步操作相关库( async和 promise),本节将分享c++标准库中最后一个多线程异步操作库 package_task的学习笔记。 描述 头文件 声明方式: template< class R, class ...Args > c...

  • 来源:公众号|计算机视觉工坊(系投稿)作者:仲夏夜之星「3D视觉工坊」技术交流群已经成立,目前大约有12000人,方向主要涉及3D视觉、CV&深度学习、SLAM、三维重建、点云后处理、自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、...

  • 点云PCL免费知识星球,点云论文速读。文章:Real-Time LIDAR-Based Urban Road and Sidewalk Detection for Autonomous Vehicles作者:Ern˝o Horváth  , Claudiu Pozna ,and Miklós Unger编译:点云PCL代码:http...

  • 文章:Semantic Histogram Based Graph Matching for Real-Time Multi-Robot Global Localization in Large Scale Environment作者:Xiyue Guo, Junjie Hu, Junfeng Chen, Fuqin Deng, T...

  • 点云PCL免费知识星球,点云论文速读。文章:Robust Place Recognition using an Imaging Lidar作者:Tixiao Shan, Brendan Englot, Fabio Duarte, Carlo Ratti, and Daniela Rus编译:点云PCL(ICRA 2021)开源代码:...

  • 文章:A Survey of Calibration Methods for Optical See-Through Head-Mounted Displays作者:Jens Grubert , Yuta Itoh, Kenneth Moser编译:点云PCL本文仅做学术分享,如有侵权,请联系删除。欢迎各位加入免费知识星球,获取PD...