写第一篇《await使用中的阻塞和并发》的时候还自信满满,觉得写的真不错,结果漏洞百出……

  更正第二篇《await使用中的阻塞和并发(二)》的时候觉得这回不会再错了……

  结果我正在写第三篇,而且连篇名都不敢延用了……

  首先完善第二篇对Foreach(Action<T>)的拆解,用很厉害的小兄弟geelaw的话说就是“是用另一个方法返回λ表达式创建的委托,并未把λ表达式换成方法。”惭愧啊,在小兄弟的指点下,修改代码如下,在Foreach(Action)这个话题上算是圆满了:

  1. public void AwaitFuncTaskListNoLambda()
  2. {
  3. var funcList = new List<Func<Task>>()
  4. {
  5. Delay3000Async,
  6. Delay2000Async,
  7. Delay1000Async
  8. };
  9.  
  10. //funcList.ForEach(async _ => await _());
  11. //funcList.ForEach(AwaitAction());
  12. //foreach (var func in funcList)
  13. //{
  14. // AwaitAction()(func);
  15. //}
  16.  
  17. Action<Func<Task>> L = this.Xxx;
  18. foreach (var func in funcList)
  19. {
  20. L(func);
  21. }
  22. }
  23.  
  24. async void Xxx(Func<Task> ft)
  25. {
  26. await ft();
  27. }
  28.  
  29. public Action<Func<Task>> AwaitAction()
  30. {
  31. return async _ => await _();
  32. }

  接下来的文字是本篇的重点,来自redjackwang菊苣的指点,他指出了我第二篇中仍存在的误区和错误。下面让我们来领略一下大牛的风采。首先从上篇我给出的结论入手:

  1. async用于异步,可以优美的替代Thread、BackgroundWorker和Task.Run等写法。
  2. await用于等待。一定是在你主动希望阻塞并等待返回结果时才使用。
  3. 在async方法里,Task在创建时就开始运行了。

  第一点需要指出这里的替代仅仅是写法的变化,async方法内部具体实现可能仍使用Thread等多线程技术来实现。这里需要明确async/await仅是一个异步的写法,而Thread\BackgroundWorker和Task是多线程。

  关于第二点,有两位菊苣分别提出异议。redjackwang的原话是“await并不会阻塞任何线程。await只是把当前方法状态保存并立即返回,不管是主线程还是后台线程都不会阻塞,而是在完成时call一个回调。”胖胖的韦恩卑鄙是这么说的:“说await是主动阻塞问题很大。那叫做响应式休眠?

  至于第三点,那是MSDN坑我,redjackwang大人竟然从MSDN上找到了更详细的答案来证明我给出的链接是错误的。在此一定要共享出来给各位,不要被我上篇错误的结论误导了,正确的表述如下:

Tasks created by its public constructors are referred to as “cold” tasks, in that they begin their life cycle in the non-scheduled TaskStatus.Created state, and it’s not until Start is called on these instances that they progress to being scheduled.  All other tasks begin their life cycle in a “hot” state, meaning that their asynchronous execution has already been initiated and their TaskStatus is an enumeration value other than Created. 

All tasks returned from TAP methods must be “hot.”  If a TAP method internally uses a Task’s constructor to instantiate the task to be returned, the TAP method must call Start on the Task object prior to returning it. Consumers of a TAP method may safely assume that the returned task is “hot,” and should not attempt to call Start on any Task returned from a TAP method.  Calling Start on a “hot” task will result in an InvalidOperationException (this check is handled automatically by the Task class). 

  为此redjackwang还给出了证明的例子,在这个例子中,如果注释掉start方法,Task是不会自动运行的。结论是Task如果是通过构造函数创建的,状态是cold的,不会自动运行,而前一篇都是通过返回Task的方法创建出来的,状态是hot,所以自动运行了,和在不在async方法中没有关系。

  1. private async void Button_Click(object sender, RoutedEventArgs e)
  2. {
  3. var v = await Foo();
  4. this.Title = v.ToString();
  5. }
  6.  
  7. private async Task<long> Foo()
  8. {
  9. var t = new Task<long>(() =>
  10. {
  11. long z = ;
  12. for (int i = ; i < ; i++)
  13. {
  14. z += i;
  15. }
  16. return z;
  17. });
  18. //t.Start();
  19. return await t;
  20. }

  本篇应不是最终的结果,后面如有进一步的发现仍会更新下去,批判的暴风雨还在继续……

批判“await使用中的阻塞和并发”——对asyc/await这对基友的误会和更正的更多相关文章

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

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

  2. await使用中的阻塞和并发(二)

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

  3. [译]async/await中使用阻塞式代码导致死锁 百万数据排序:优化的选择排序(堆排序)

    [译]async/await中使用阻塞式代码导致死锁 这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的 ...

  4. [译]async/await中使用阻塞式代码导致死锁

    原文:[译]async/await中使用阻塞式代码导致死锁 这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Clea ...

  5. 深入理解java:2.3.4. 并发编程concurrent包 之容器ConcurrentLinkedQueue(非阻塞的并发队列---循环CAS)

    1.    引言 在并发编程中我们有时候需要使用线程安全的队列. 如果我们要实现一个线程安全的队列有两种实现方式:一种是使用阻塞算法,另一种是使用非阻塞算法. 使用阻塞算法的队列可以用一个锁(入队和出 ...

  6. js异步回调Async/Await与Promise区别 新学习使用Async/Await

    Promise,我们了解到promise是ES6为解决异步回调而生,避免出现这种回调地狱,那么为何又需要Async/Await呢?你是不是和我一样对Async/Await感兴趣以及想知道如何使用,下面 ...

  7. await在forEach不起作用解决【await is a reserved word】

    原文链接:https://blog.csdn.net/ssbb1995/article/details/82084800 1.await 只能在 async中使用,如: async function ...

  8. Iterator与Asyc/Await的实现

    https://wanago.io/2018/04/23/demystifying-generators-implementing-async-await/

  9. 今天写了一个可以测试并发数和运行次数的压力测试代码。(Java)

    今天写了一个可以测试并发数和运行次数的压力测试代码 介绍一下为什么会写这么一个工具. 介绍一个这个工具怎么用的. 背景 最近在开发CoapServer端,以及模拟设备侧发送数据调用开发好的CoapSe ...

随机推荐

  1. 常规Java工具,算法,加密,数据库,面试题,源代码分析,解决方案

    原文链接:http://www.tvtvso.top/?thread-5.htm 有家杂志曾对全国60岁以上的老人进行了这样一次问卷调查:你最后悔什么? 列出10项人们生活中容易后悔的事情,供被调查者 ...

  2. thinkphp5中Indirect modification of overloaded element of XXX has no effect的解决办法

    最近在使用Thinkphp5做foreach循环嵌套的时候报错:Indirect modification of overloaded element of XXX has no effect,网上搜 ...

  3. MATLAB 条形图或饼状图 图案填充

    function [im_hatch,colorlist] = applyhatch_pluscolor(h,patterns,CvBW,Hinvert,colorlist, ... dpi,hatc ...

  4. VB.Net与C# 的语法比较

    最近看代码或写代码时,经常把VB与C#的基本语法搞混,为方便查看,特对其异同进行对比: 變數初始化 VB.NET 自動將所有的變數初始化成 0 或 nothing.C# 在你未初始化變數之前不准你用該 ...

  5. WebLogic Server StuckThreadMaxTime value is exceeded during configuration

    WebLogic Server StuckThreadMaxTime value is exceeded during configuration If you are configuring Web ...

  6. 智能指针--C++

    智能指针(一):STL auto_ptr实现原理 智能指针实际上是一个类(class),里面封装了一个指针.它的用处是啥呢? 指针与内存 说到指针自然涉及到内存.我们如果是在堆栈(stack)中分配了 ...

  7. UNITY polygon collider不随物体旋转

    U3D中的一般包围框如 boxcollider, meshcollider, capsule collider等都会随物体旋转而旋转.然而polygon collider却不会. 补充:原来所有2D包 ...

  8. 迷你MVVM框架 avalonjs 0.96发布

    本版本主要是性能优化与 fix BUG,改进如下: 处理notifySubscribers中的BUG,它在标准浏览器不会移除那些无用的视图刷新函数.详见这里 重构modelBindling.SELEC ...

  9. 背景半透明rgba最佳实践

    by 一丝 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...

  10. LevelDB SSTable文件

    [LevelDB SSTable文件] LevelDb不同层级有很多SSTable文件(以后缀.sst为特征),所有.sst文件内部布局都是一样的.上节介绍Log文件是物理分块的,SSTable也一样 ...