zoukankan      html  css  js  c++  java
  • C#中的异步编程Async 和 Await

    谈到C#中的异步编程,离不开Async和Await关键字

    谈到异步编程,首先我们就要明白到底什么是异步编程。 平时我们的编程一般都是同步编程,所谓同步编程的意思,和我们平时说的同时做几件事情完全不同。 在计算机的世界里,同步编程的意思说 按照顺序来执行,或者说是 一个接着一个地有序的来执行, 比如目前我们在代码中有三件任务来执行,那么必须先执行完第1件,再执行第2件,接下来再执行第3件。 在这个过程中,第1件没有完成,你是没法开始做第2件事情的,必须等待。

    比如一个人烧开水需要10分钟,5分钟找杯子,5分钟找茶叶。 这件事情在同步编程的世界里需要20分钟完成,因为必须先烧开水10分钟,等烧完开水后。 才开始做第2件事情找杯子,花费5分钟。 找完杯子后,才开始做第3件事情-找茶叶,又花费5分钟。这样,整个过程就花费了20分钟。但其实这3件事情可以同时做,互相并不影响,这就是异步编程的概念了

    由上面这个例子中可以发现,在计算机编程世界里,【异步编程】才是真正的同时进行事情,而【同步编程】是一件一件的有序执行。 上面的例子,如果采用异步编程,那么10分钟就可以全部完成。

    在C#中,异步编程中有三个方面需要注意:

    1.为了表示一个方法是异步方法,需要使用async关键字来修饰该方法签名

    2. 异步方法的返回值类型 --- 只有 void, Task 和 Task<T>

    3. 在异步方法内部,你需要使用await关键字来修饰一个可以等待的【可等待】类型,来实现异步

    我们通过例子来比较同步编程和异步编程的不同

    举例:  比如页面上有个【计算】按钮,点击该按钮 程序将会进行一个复杂运算,该运算将花费45秒的时间,运算完后返回计算结果,现实在页面的一个textbox文本框里面

    private void btnCalculate_Click(object sender, EventArgs e)
    {
         int calResult =   ToCalculate();
         this. Textbox1.Text = calResult;
    
    }
    
    private int ToCalculate()
    {     
       // 这里有复杂的计算过程,将耗时45秒, 我们这里通过让线程休眠45秒钟来模拟
         System.Threading.Thread.Sleep(45000); 
        
          return 100;
    
    }

    在上面代码中,我们假设方法ToCalculate方法要进行复杂的计算。在这里,我们通过让当前线程挂起45秒,来模拟耗时45秒的复杂计算过程.

    我们可以想象得到,上面得代码中,当用户在界面上点击btnCalculate按钮时,UI在接下来的45秒里将毫无反应,程序将只干一件事情,就是允许ToCalculate方法来进行耗时45秒的复杂计算。45秒之后,才会把计算结果返回到Textbox1中,再接下来做其他的操作

    这个显然非常的用户不友好,因为用户会发现他需要等在那里45秒,什么事情也不能干。如果在这个等待过程中,用户在UI上还能同时操作干其他的事情呢?  这个就需要涉及到异步编程的概念

    【异步编程】的操作过程如下: 

    执行异步方法,当遇到await关键字时,表示要开始执行一个异步方法,await关键字来修饰的方法是一个方法。这个时候程序会做两件事情

    第1件: 程序去执行await关键字修饰的异步方法

    第2件: 在做第1件的同时,把控制权立即返回给调用者,也就是说调用者这个时候,可以在等待异步方法执行的过程中,同时去做其他事情,因为控制权已经在它手中了。

    看看上面的例子,如果采用异步方法,当用户在界面上点击btnCalculate按钮时,程序会执行异步方法ToCalculate. 但与此同时,控制权也马上回到UI手上,也就是说在后台进行耗时45秒的复杂计算的同时,用户可以同时在UI上进行其他操作。当异步计算结束,把计算结果显示在UI的Textbox1上。

    了解了整个过程后,我们使用异步方法来改写上面的代码

    private async void btnCalculate_Click(object sender, EventArgs e)
    {
         int calResult =   await ToCalculate();
         this. Textbox1.Text = calResult;
    }
    
    private Task<int> ToCalculate()
    {     
       //将复杂计算的过程放入一个Task<int>中,新开线程
       var t = Task.Run(()=>
       {
          System.Threading.Thread.Sleep(45000);
          return 100; 
       }); 
       //返回的是这个Task<int>
       return t;
    }

     从上面的代码变动中,我们可以看到几处变动情况

    1. 在方法的签名中,在public后面加入了async关键字, 将该方法标识成一个异步方法。 这样,让程序知道这个方法是一个异步方法, 此时它内部的await才会被认为是一个关键字。

        或者说,如果在方法的签名中没有async关键字, await会被认为是一个普通的变量名,也就是说,它会被当成普通的C#标识符来处理(类似于 string await ="test";)  

    2. 在async标识的异步方法中,在需要异步调用的方法ToCalculate方法前面,使用await关键字

    3. 异步调用的方法ToCalculate,只能是三种返回值类型中的一种void, Task 和 Task<T>。 在这个例子中,是Task<T>

     

     

  • 相关阅读:
    软件测试七年之痒,依然热爱!我还是从前那个少年!
    我想从功能测试转向自动化测试,怎么办?
    python中的一些内置函数
    python中eval()
    集合
    列表的切片:取出来还是一个列表,可用在复制列表元素的操作
    字符串常用的方法
    dict字典,以及字典的一些基本应用
    list列表(也叫数组),以及常用的一些方法
    jsonpath的用法
  • 原文地址:https://www.cnblogs.com/wphl-27/p/10534704.html
Copyright © 2011-2022 走看看