常见的异步方式async 和 await

以前研究过c#的async和await关键字,幕后干了什么,可是不知道为何找不到相关资料了。如今从新研究一遍,顺便记录下来,方便之后查阅。程序员

基础知识

async 关键字标注一个方法,该方法返回值是一个Task、或者Task<TResult>、void、包含GetAwaiter方法的类型。该方法一般包含一个await表达式。该表达式标注一个点,将被某个异步方法回跳到该点。而且,当前函数执行到该点,将马上返回控制权给调用方。c#

以上描述了async方法想干的事情,至于如何实现,这里就不涉猎了。多线程

我的看法

由此能够知道,async 和await关键字主要目的是为了控制异步线程的同步,让一个异步过程,表现得好像同步过程同样。并发

好比async 方法分n个任务去下载网页并进行处理:先await下载,而后马上返回调用方,以后的处理就由异步线程完成下载后调用。这时候调用方能够继续执行它的任务,不过,若是调用方马上就须要async的结果,那么应该就只能等待,不过大多数状况:他暂时不须要这个结果,那么就能够并行处理这些代码。异步

可见,并行性体如今await 上,若是await 点和最终的数据结果距离越远,那么并行度就越高。若是await的点越多,相信也会改善并行性。async

资料显示,async 和await 关键字并不会建立线程,这是很关键的一点。他们只是建立了一个返回点,提供给须要他的线程使用。那么线程到底是谁建立?注意await 表达式的组成,他须要一个Task,一个Task并不表明必定要建立线程,也能够是另外一个async方法,可是层层包裹最里面的方法,极可能就是一个原生的Task,好比await Task.Run(()=>Thread.Sleep(0)); ,这个真正产生线程的语句,就会根据前面那些await点,逐个回调。函数

从这点来看,async 方法,未必就是一个异步方法,他在语义上更加贴近“非阻塞”, 当遇到阻塞操做,马上用await定点返回,至于其余更深一层的解决手段,它就不关心了。这是程序员须要关心的,程序员须要用真正的建立线程代码,来完成异步操做(固然这一步可由库程序员完成)。高并发

注意async的几个返回值类型,这表明了不一样的使用场景。若是是void,说明客户端不关心数据同步问题,它只须要线程的控制权马上返回。能够用在ui 等场合,若是是Task,客户端也不关心数据,可是它但愿可以控制异步线程,这多是对任务执行顺序有必定的要求。固然,最多见的是Task<TResult>。oop

综上,async和await并非为了多任务而设计的,若是追求高并发,应该在async函数内部用Task好好设计一番。在使用async 和await的时候,只须要按照非阻塞的思路去编写代码就能够了,至于幕后怎么处理就交给真正的多线程代码建立者吧。ui

示范代码

        static async Task RunTaskAsync(int step)
        {
            for(int i=0; i < step; i++)
            {
                await Task.Run(()=>Thread.Sleep(tmloop));//点是静态的,依次执行
                Thread.Sleep(tm2);
            }
            Thread.Sleep(tm3);
        }

//客户端
            Task tk= RunTaskAsync(step);
            Thread.Sleep(tm1);//这一段是并行的,取max(函数,代码段)最大时间
            tk.Wait( );//这里表明最终数据

为了达到高度并行,应该用真正的多线程代码:

        static async Task RunTaskByParallelAsync(int step)
        {
            await Task.Run(()=>Parallel.For(0,step,
                s=>{loop(tmloop);
                    loop(tm2);
                    }
            ));
            loop(tm3);
        }

并行编码方法

并行执行有几个方法,第一个是建立n个Task,一块儿启动。问题是怎么处理await点。每一个task写一个await点是不行的,由于遇到第一个await就马上返回,而不会开启全部任务并行执行。所以await不能随便放。那么如何为一组Task设定await点呢?能够经过Task.WhenAll 这个方法,他会等待一组Task执行完毕返回。

特定状况下,能够用Parallel.For 来开启一组任务,可是这个类并无实现async模式,也就是它会阻塞当前线程,因此须要用一个Task来包裹它。

可见,非阻塞和并行不彻底是一回事。

相关文章
相关标签/搜索