zoukankan      html  css  js  c++  java
  • 我也来说说C#中的异步:async/await

      最近看了一些园友们写的有关于异步的文章,受益匪浅,写这篇文章的目的是想把自己之前看到的文章做一个总结,同时也希望通过更加通俗易懂的语言让大家了解"异步"编程。

    1:什么是异步

      应用程序在启动后,会产生一个进程,进程是构成应用程序资源的集合。在进程内部有称之为线程的对象,线程才是真正负责执行运行命令的。

      线程:

        1:默认情况下,一个应用程序只会有一个线程,从程序开始到结束。

        2:一个进程如果有多个线程,那么多个线程将会共享进程内的资源。

        3:线程不是派生于不同的线程。

      一般来说,我们写的程序都是单线程的,但是这种程序对用户体验很不好,拿WinFrom来说,假设在单线程的情况下,用户点击某个Button执行了一个耗时操作,那么在此操作执行完成前,窗体程序是无法拖动位置的,简单来说,如果这个时候你去操作这个应用程序,那么这个应用程序的状态就会变成:未响应。造成这种问题的最根本原因是这个程序一直都是在单线执行,如果其中某个步骤耗时过长,那么后面的操作只有等待。这种写法不仅浪费资源而且还严重影响性能。而异步则可以帮我们很好的解决这一问题.

    2:初识异步

      大壮是个好男人,每天晚上回家后都会煮饭,洗菜,炒菜,然后等饭熟开始吃饭,这几个步骤如果按照单线程处理方式如下:

      

     1 static void Main(string[] args)
     2 {
     3             var stopWatch = new Stopwatch();
     4             stopWatch.Start();
     5             Console.WriteLine("大壮开始煮饭......");
     6             System.Threading.Thread.Sleep(5000);  //模拟耗时5秒
     7             Console.WriteLine("饭煮熟了开始洗菜......");
     8             System.Threading.Thread.Sleep(3000); //模拟耗时3秒
     9             Console.WriteLine("菜洗好了,开始炒菜.......");
    10             System.Threading.Thread.Sleep(3000);  //模拟耗时3秒
    11             Console.WriteLine($"开始吃饭,做饭总耗时{stopWatch.ElapsedMilliseconds}");
    12             stopWatch.Start();
    13             Console.ReadLine();
    14}

      其运行结果如下:

        

      虽然大壮把饭菜做好了,但是他的老婆不愿意了,开始说他:你说你是不是傻啊,你为什么非要等饭煮熟了采取洗菜炒菜呢?为什么就不能把饭煮了后就去洗菜炒菜,然后在等饭熟呢?大壮一拍脑袋,对啊,说改咋就改:

      

     1 static void Main(string[] args)
     2         {
     3             var stopWatch = new Stopwatch();
     4             stopWatch.Start();
     5             Console.WriteLine("大壮开始煮饭......");
     6             var isEat = CookriceAsync();
     7             Console.WriteLine("饭煮熟了开始洗菜......");
     8             Thread.Sleep(3000); //模拟耗时3秒
     9             Console.WriteLine("菜洗好了,开始炒菜.......");
    10             Thread.Sleep(3000);  //模拟耗时3秒
    11             if (isEat.Result)
    12                 Console.WriteLine($"开始吃饭,做饭总耗时{stopWatch.ElapsedMilliseconds}");
    13             stopWatch.Stop();
    14             Console.ReadLine();
    15         }
    16 
    17 
    18         private static async Task<bool> CookriceAsync()
    19         {
    20             await Task.Run(() =>
    21             {
    22                 Thread.Sleep(5000);//模拟耗时5秒;  
    23             });
    24             return true;
    25 
    26         }
    异步执行

      其结果运行如下:

      

      通过上面的例子我们不难发现程序运行所耗时明显变短,其运行结果是还是一样的。当程序在执行方的时候,如果碰到异步方法,程序则会跳出异步方法继续执行没有执行的命令,异步方法的执行不会停止。当遇到异步对象点Result的时候,如果异步程序没有执行完,那么Result方法会一直阻塞程序的运行,直到其异步方法执行完毕。

    3:初探async/await

      对比未使用异步和使用异步后的代码我们不难发现,我们把做饭的步骤封装成了一个CookriceAsync方法,但是该方法申明出多了一个async,并且返回结果明明是bool却变成了Task<bool>,而且代码中还冒出一个await,why?它们都是干嘛用的?别急,且听我一一道来。

      先说下异步方法的声明: 

           (1)关键字:方法头使用 async 修饰。
           (2)要求:包含 N(N>0) 个 await 表达式(不存在 await 表达式的话 IDE 会发出警告),表示需要异步执行的任务。【备注】感谢 czcz1024 的修正与补充:没有的话,就和普通方法一样执行了。
           (3)返回类型:只能返回 3 种类型(void、Task 和 Task<T>)。Task 和 Task<T> 标识返回的对象会在将来完成工作,表示调用方法和异步方法可以继续执行。
           (4)参数:数量不限。但不能使用 out 和 ref 关键字。
           (5)命名约定:方法后缀名应以 Async 结尾。
           (6)其它:匿名方法和 Lambda 表达式也可以作为异步对象;async 是一个上下文关键字;关键字 async 必须在返回类型前。

      异步方法可分成三部分:

           (1)调用方法:在方法调用异步方法,然后在异步方法执行其任务的时候继续执行;
           (2)异步方法:该方法异步执行工作,然后立刻返回到调用方法;
           (3)await 表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个 await 表达式(不存在 await 表达式的话 IDE 会发出警告)。

      

      关于 async 关键字:

        ①在返回类型之前包含 async 关键字

        ②它只是标识该方法包含一个或多个 await 表达式,即,它本身不创建异步操作。

        ③它是上下文关键字,即可作为变量名。

      

     现在先来简单分析一下这三种返回值类型:void、Task 和 Task<T>

      1:Task<T>:调用方法要从调用中获取一个 T 类型的值,异步方法的返回类型就必须是Task<T>。调用方法从 Task 的 Result 属性获取的就是 T 类型的值。

      2:Task:不需要返回任何结果,但是需要知道异步方法的状态。不过就算方法内含有return语句,也不会返回任何东西。

      3:Void:调用方法执行异步方法,但又不需要做进一步的交互。 

    本文大部分文字内容来源于:http://www.cnblogs.com/liqingwen/p/5831951.html 写得不错,本篇文章只是进行一些总结。

  • 相关阅读:
    intel 1211网卡驱动
    winform 右侧关闭按钮事件
    base64 教程
    js 预览图片 转base64
    docker常用命令
    docker安装
    jenkins集成sonar
    jenkins自动打包部署linux
    mac生成ssh公私匙
    jenkins统计单元测试的覆盖率
  • 原文地址:https://www.cnblogs.com/dazhuangtage/p/5891104.html
Copyright © 2011-2022 走看看