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

摘要:
当我写第一篇文章《使用await时的阻塞和并发》时,我确信它写得很好,结果漏洞百出……当我更正第二篇文章《在使用await(II)时,我觉得这次不会出错……需要明确的是,async/await只是一种异步写方法,ThreadBackgroundWorker和Task是多线程的。redjackwang的原话是“await不阻塞任何线程。await只是保存当前方法状态并立即返回。主线程和后台线程都不会阻塞,而是在完成时调用回调。”

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

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

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

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

        public void AwaitFuncTaskListNoLambda()
        {
            var funcList = new List<Func<Task>>()
            {
                Delay3000Async,
                Delay2000Async,
                Delay1000Async
            };
 
            //funcList.ForEach(async _ => await _());
            //funcList.ForEach(AwaitAction());
            //foreach (var func in funcList)
            //{
            //    AwaitAction()(func);
            //}
 
            Action<Func<Task>> L = this.Xxx;
            foreach (var func in funcList)
            {
                L(func);
            }
        }
        
        async void Xxx(Func<Task> ft)
        {
            await ft();
        }

        public Action<Func<Task>> AwaitAction()
        {
            return async _ => await _();
        }
    

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

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

  第一点需要指出这里的替代仅仅是写法的变化,async方法内部具体实现可能仍使用Thread等多线程技术来实现。这里需要明确async/await仅是一个异步的写法,而ThreadBackgroundWorker和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方法中没有关系。

private async void Button_Click(object sender, RoutedEventArgs e)
{
    var v = await Foo();
    this.Title = v.ToString();
}
 
private async Task<long> Foo()
{
    var t = new Task<long>(() =>
    {
        long z = 0;
        for (int i = 0; i < 100000; i++)
        {
            z += i;
        }
        return z;
    });
    //t.Start();
    return await t;
}

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

 

 

免责声明:文章转载自《批判“await使用中的阻塞和并发”——对asyc/await这对基友的误会和更正》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇动态规划解决01背包问题ubuntu-16.04使用MDK3伪造wifi热点和攻击wifi热点至死下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

async与await总结

全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/11533174.html,多谢,=。=~  抛出3个疑问: 1、async是干哈的? 2、await在等啥? 3、await等到了又要干哈?  先说说AsyncFunction  AsyncFunction构造函数用来创建新的异步函数对象,JavaScri...

使用 async-await 简化代码的检讨

  从API版本升级到4.6之后, Unity支持了async和await语法, 并且根据测试来看, 它运行在主线程里, 跟一般的C#编译不大一样, 这就很有操作空间了, 先来看看普通C# Console工程和Unity中运行的差别:   1. C# Console using System; namespace AsyncTest { clas...

学习迭代器实现C#异步编程——仿async/await(一)

  .NET 4.5的async/await真是个神奇的东西,巧妙异常以致我不禁对其实现充满好奇,但一直难以窥探其门径。不意间读了此篇强文《Asynchronous Programming in C# using Iterators》,犹如醍醐灌顶,茅厕顿开,思路犹如尿崩。美玉不敢独享,故写此篇,将所学中一些思考与诸君共享,期抛砖引玉,擦出一些基情火花……...

C#异步编程之(三):深入 Async 和 Await 的实现及其成本

From: http://msdn.microsoft.com/zh-cn/magazine/hh456402.aspx异步性能:了解 Async 和 Await 的成本Stephen Toub 异步编程长时间以来一直都是那些技能高超、喜欢挑战自我的开发人员涉足的领域 — 这些人愿意花费时间,充满热情并拥有心理承受能力,能够在非线性的控制流程中不断地...

springboot(十九)-线程池的使用

我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行。 话不多说,编码开始: 1.创建springboot工程 创建一个springboot的web工程threadpooldemoserver,pom.xml内容如下: <project xmln...

RocketMQ的安装配置:配置jdk环境,配置RocketMQ环境,配置集群环境,配置rocketmq-console

RocketMQ的安装配置 演示虚拟机环境:Centos64-1 (D:linuxMorecentos6_64) root / itcast : 固定IP 192.168.52.128 一,配置JDK环境 1,解压jdk到指定的目录 tar -xvf jdk-8u171-linux-x64.tar.gz -C /usr/local cd /usr/loca...