理解C#里的async和await


世界很單純,復雜的是人吶~

async和await也是如此。語法和含義很簡單,程序員想多了,這東西就顯得特別復雜。

async

含義:異步。它修飾的方法里,通常有其他異步操作。普通操作(通常是前半截)執行完了,控制權就返回“調用它的方法(主方法)”了(通常帶回一個Task)。當異步操作(通常是后半截)執行完之后,主方法可以從它返回的Task里拿需要的東西(也可以不拿)。前后半截的分界線,就是await。

  ps:這東西一般出現在方法頭部,但不屬於方法簽名的一部分。也就是說,不能出現在接口和抽象類的方法說明中,可以出現在實現的方法頭。

await

  含義:在可等待方法中,await就是前后兩段代碼的分界線。它前面的代碼被編譯成一個方法,它和它后面的代碼被編譯成另一個方法。第一個方法,通常由主線程執行;第二個方法,通常由新建的線程(一般在異步嵌套調用的最里層新建)執行。它等待的,是一個異步操作的結果。

  注意:子方法運行到await的時候,主方法繼續執行,而子方法等待它等待的結果,然后執行它后面的語句。

用途

  通常,設計一個異步(可等待)方法,就是為了方便別人調用它,它執行異步操作的時候,別人還能干自己的事。


問題來了:怎么用?

不止是語法問題,還要跟我們平時的編程習慣……最好是同步編程習慣貼合,才舒適。

先看一段耗時操作:

先花1秒,計算n!

static int jc(int x)
{
    int y = 1;
    Thread.Sleep(1000);
    for (int i = 2; i <=x; i++)
    {
        y *= i;
    }
    return y;
}

針對耗時操作,肯定會想到異步調用。常規異步調用:

var t=Task.Run(() => jc(5));//求5!,開始算吧
Console.WriteLine("我忙我的");
Console.WriteLine($"5!={t.Result}");

既然耗時操作,一般都是異步調用。那我就給它包裝個異步方法,以期更好調用:

static async Task<int> jc1(int x)
{
    var t = Task.Run(() => jc(x));
    Console.WriteLine($"異步計算{x}!已經開始了,主程序繼續...");
    await t;
    Console.WriteLine($"{x}!算完了");
    return t.Result;
    //return await Task.Run(() => jc(x));//極簡寫法
}

遇到await,主程序得到一個“必有int返回值”的承諾,就繼續執行。子程序當Task執行完畢的時候,await向下繼續執行。

調用方法就可以寫成:

var t = jc1(5);//異步求5!,開始算吧,我繼續。。。
Console.WriteLine("我忙我的");
Console.WriteLine($"5!={t.Result}");

第一行開始計算,第三行索要結果(誰讓你承諾必有結果呢)。少了task,更符合人類習慣了。

第三行“t.Result”那里如果是“await t”,這個主方法也就是異步方法了。 


總結:

一、無論是自己寫的,還是微軟寫的異步方法(下面叫做S)里,必然有一個多線程的所謂“耗時操作”。

二、調用時,可以

  1. await S();阻塞式異步調用;
  2. S().wait();阻塞式同步調用;
  3. var t=S();/*並行操作*/;await t;並行異步調用;
  4. var t=S();/*並行操作*/;t.wait();並行同步調用。

所謂異步/同步調用,即所在的方法是異步/同步方法。

三、不管套多少層的異步,一般也就兩個線程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM