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

在.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<Task>{Delay3000Async(),Delay2000Async(),Delay1000Async()};tasks.ForEach(async _ => await _);

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

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

            var funcList = new List<Func<Task>>(){Delay3000Async,Delay2000Async,Delay1000Async};funcList.ForEach(async _ => await _());

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

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

            Func<Task> func3 = Delay3000Async;Func<Task> func2 = Delay2000Async;Func<Task> 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<Func<Task>>的例子开始迷糊了。参考了Reflector反编译的结果……我想说……没看出来有什么区别……本篇先到这里。一旦琢磨出个所以然,我再发第二篇好了。

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

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

       static async Task TestForeach(){var funcList = new List<Func<Task>>(){Delay3000Async,Delay2000Async,Delay1000Async};foreach (var item in funcList){          //这里干了件蠢事,不要主动阻塞在这里,就可以并发了……await item();}}    

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

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

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

await使用中的阻塞和并发(一)相关推荐

  1. await使用中的阻塞和并发

    本文讨论,通过将Lambda还原成最普通的代码段,来解释上篇提出的疑问.并更正上篇中一些不太正确的写法.最后会给出无需等待Async方法返回值时,对Async方法使用await的建议,供大家参考. 第 ...

  2. 15分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行,太实用了!

    作者:Martin cnblogs.com/mhq-martin/p/9035640.html 基本概念 1 进程和线程 进程(Process): 是Windows系统中的一个基本概念,它包含着一个运 ...

  3. python非阻塞多线程socket_Python实现web服务器之 单进程单线程非阻塞实现并发及其原理...

    在Python实现web服务器入门学习多进程.多线程实现并发HTTP服务器中,我们知道可以分别通过多进程.多线程的方式实现并发服务器,那么,是否可以通过单进程单线程的程序实现类似功能呢? 实际上,在P ...

  4. 15分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行

    基本概念 1 进程和线程 进程(Process): 是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程 ...

  5. 进程线程、同步异步、阻塞非阻塞、并发并行、多线程

    一: 进程和线程 1: 进程(Process) 是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程.线 ...

  6. 队列阻塞_Java并发|阻塞队列ArrayBlockingQueue解析

    之前的文章我们学了 ConcurrentHashMap. ConcurrentLinkedQueue 等线程安全容器,而且也说了 Java并发包中的 Concurent 开头的并发容器都是非阻塞的,是 ...

  7. CountDownLatch 的 .await() 的线程阻塞 和countDown() 计时唤醒

    1.CountDownLatch end = new CountDownLatch(N); //构造对象时候 需要传入参数N 2.end.await()  能够阻塞线程 直到调用N次end.count ...

  8. 多线程编程:阻塞、并发队列的使用总结

    最近,一直在跟设计的任务调度模块周旋,目前终于完成了第一阶段的调试.今天,我想借助博客园平台把最近在设计过程中,使用队列和集合的一些基础知识给大家总结一下,方便大家以后直接copy.本文都是一些没有技 ...

  9. Linux下套接字详解(五)----基于fork多进程的TCP套接字(阻塞/同步/并发)

    简介 一个简单的改进方案是在服务器端使用多线程(或多进程).多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接.具体使用多进程还是多线程,并没有 ...

最新文章

  1. Windows下的鱿鱼(Squid)
  2. html5在线api,HTML5 历史记录API
  3. if you can not make a solid foundation
  4. boost::math::quadrature::tanh_sinh用法的测试程序
  5. 使用 JavaScript 实现简单候选项推荐功能(模糊搜索)【收藏】【转】
  6. 【Kafka】KafkaConsumer is not safe for multi-threaded access
  7. 逆水寒7.25服务器维护,逆水寒7月26日更新维护公告 更新内容汇总
  8. ggplot2图集汇总(一)
  9. Atitit 登录账号管理法passport 目录 1. 总则 1 1.1. 身份分类登录账号 管理员 操作人员 普通用户 1 1.2. 安全考虑,必须单独分开的账号储存表,使用不同等加密技术与秘
  10. 机器学习- 吴恩达Andrew Ng Week1 知识总结 Introduciton
  11. unity天空盒渐变_unity如何制作绚丽的太空天空盒?
  12. android软件音量控制
  13. Windows10添加自定义右键菜单
  14. 网络间谍:你的共享文件夹网络监视器
  15. 智能暖风机——4.暖风机外设驱动实现
  16. 2020-8-15词汇
  17. IOS 后台运行 播放音乐
  18. macbook系统占用硬盘大_Sketch占满MacBook200G硬盘的解决方法
  19. mysql定时任务自动备份
  20. android 游戏sdk嫁接方式

热门文章

  1. SOAPUI请求及mockservice 使用
  2. 30 个 php 操作 redis 常用方法代码例子
  3. Java程序猿面试题集(181- 199)
  4. map 小模板~~~ 写的不好 继续添加
  5. 一些可能没用过的调试窗口
  6. 《OpenCV3编程入门》学习笔记6 图像处理(二)非线性滤波:中值滤波、双边滤波
  7. java跨函数跳转_C语言中将绝对地址转换为函数指针以及跳转到内存指定位置处执行的技巧...
  8. 人名翻译_考研英语翻译:句子中出现人名怎么办?
  9. 网站的 计算机主机作用是什么意思,网关是什么意思?网关的作用是什么?
  10. c 与java 反射性能_谈谈Java 反射的快慢