.Net-C#异步程序知识点梳理

  • 线程:
    每个Windows进程都有用于进入程序的进入点(entry point)的主线程(Main Thread),例如.Net framework执行程序(控制台、Windows WPF等应用程序)使用Main()方法作为程序的进入点,调用该方法时会自动建立主线程。
    线程是Windows进程中的独立执行单元,每个线程都有一个主线程(在执行进入点时建立)并且每个线程还可以以程序方式建立新的线程。
    线程的分配与启动需要一定的时间与成本开销,所以这个过程并不是实时的。

  • Task类:
    与Thread相比,Task是更抽象的概念,MSDN说明就简单一句:“表示异步操作”,即为能以多线程执行的异步操作,从net framework4.5开始,要建立实现Task后台线程最简单的方式就是使用静态方法Task.Run(),在.Net Framework 4.0可以调用Task.Factory.StartNew方法,可以实现相同的效果

            持续工作会告诉Task在完成后继续执行后续的作业,持续工作通常由一个回调方法来实现,它会在任务完成后执行一次。将一个Task加上持续工作有两种方法,

    1. 第一种是调用Task.ContinueWith方法
    2. 第二种是.Net Framework4.5新增的Awaiter方法,它非常重要,因为C#5.0的异步功能就是使用这种方式。先看程序代码来说明
    Task<int> task=Task.Run(
         ()=>Enumerable.Range(1,5000000).Count(n=>(n%3)==0);
         var awaiter=task.GetAwaiter();
         awaiter.OnCompleted(()=>
       {
         int result=awaiter.GetResult();
         Console.WriteLine("整除3的个数有:"+Result);
         Console.WriteLine("Task执行中...")
         Console.ReadLine();
       });

    调用Task.GetAwaiter方法会返回一个awaiter(等待者)对象,它会让先前的Task在完成或出错之后执行一个委派,如果先前的Task出现错误,那么当接续工作调用awaited.GetResult()时就会弹出例外。使用GetResult的好处是,当先前的Task出错时,例外可以直接弹出,而不会封装在 aggregateException中。

          Task.Delay方法在建立时间延迟之后才会完成的工作,简单地说,它就是Thread.Sleep的异步版本

           Parallel类 主要提供并行循环和区域的支持,主要有三个方法For、Foreach、Invoke,主要说一下Invoke方法,Invoke方法会简化启动一组并行操作,它接受一组Action[]数组。

  • Async与await关键词 有async修饰词不一定有await运算符,但有await运算符一定有async修饰词,按照微软的建议,开发人员自己编写的异步方法最好也采用“Async”结尾。
  • 异步与线程池
    当在应用程序中大量使用多线程技术时,首先有一点必须注意。.net framework 会在IIS维护一个线程池,当iis接受到一个请求时,就会从线程池读取一个线程处理的请求,如果使用同步处理程序方式处理此请求,此线程直到程序处理完毕之前,都会一直为自己请求服务,并且此线程无法再为其他请求进行服务,就是所谓的封锁。 如果线程池够大,就没什么问题,不过线程池的数量是有限的,当有大量突发请求,或可应请求线程都忙于后端高延迟性网络任务时,所有线程池的线程都被封锁,这种情况称为线程耗尽。发生线程耗尽,IIS会开始将请求排入队列,如果队列已满时,IIS就会拒绝请求,并呈现http503状态,如果异步应用程序正常,但是偶尔会发生http503状态,那么可以开课,事故为县城靠近的情况,可以试着调高队列长度,例如调高至一千。
  • 多线程与异步
    Task->新线程->读取网络资源
    多线程只是换一条线程来代替原本会被锁定的主线程,也就是用线程资源(CPU与内存)换可响应的接口。如果换成异步呢?
    异步->线程池->读取网络资源
    在线程池中时使用DMA(Direct Memory Access,直接内存访问)模式,直接内存访问是一种不经过CPU而直接进行内存数据读取的机制。CLR提供的异步程序模型就是让开发者充分利用DMA功能来降低CPU压力
     所以结论是:
       -CPU Bound:适合采用多线程;
       -IO  Bound:适合采用异步;

下一步是时候看看 .Net Core了。

posted @ 2017-10-31 00:50  tuohaibei  阅读(692)  评论(0编辑  收藏  举报