1. 程式人生 > 其它 >C#中的非同步程式設計--探索await與async關鍵字的奧妙之處,原來理解和使用非同步程式設計可以這麼簡單

C#中的非同步程式設計--探索await與async關鍵字的奧妙之處,原來理解和使用非同步程式設計可以這麼簡單

技術標籤:C#教程c#

前言
await與async是C#5.0推出的新語法,關於await與async有很多文章講解。但看完後有沒有這樣一種感覺,感覺這東西像是不錯,但好像就是看不太懂,也不清楚該怎麼使用。雖然偶有接觸,但是一直都沒有真正搞明白。

我也是才剛剛摸索明白,把學習結果和大家探討一下看掌握得對不對。個人的學習習慣就是,有複雜的東西可以簡單說明白,就會分享出來~

(閱讀本文需要具備多執行緒及任務程式設計的基礎)

重點
在學習async/await最難的是什麼呢?就是理解它的工作方式!

1.所有的async方法返回型別必然是Task或Task,這是非同步處理的基礎!

2.在async方法中遇到await關鍵字後,當前執行緒立即返回(到呼叫方),繼續之前的處理邏輯;await關鍵字之後的程式碼邏輯,將交由新的執行緒處理;當新的執行緒處理完成後,可以從新的執行緒返回處理結果到呼叫(處)執行緒當中,結束等待。

3.在一個async方法中,會根據await關鍵字進行分割,拆分到不同的執行緒處理同一個方法的不同部分!

4.把一個方法程式碼的不同部分拆分到多個執行緒處理,這是非同步方法和同步方法的最大不同!

把上面幾點搞明白了,其實非同步程式設計也就大概清楚了吧。。

簡單非同步呼叫

   class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("{0}->Main.非同步方法執行前", Thread.CurrentThread.ManagedThreadId.
ToString());//輸出非同步處理之前的執行緒ID DoAsync(1000).Wait();//執行非同步處理,並等待該非同步方法執行完成後才繼續 Console.WriteLine("{0}->Main.非同步方法執行後", Thread.CurrentThread.ManagedThreadId.ToString());//輸出非同步處理之後的執行緒ID Console.Read(); } /// <summary> /// 執行非同步處理 /// </summary>
/// <param name="times">模擬處理時長</param> /// <returns></returns> public static async Task DoAsync(int times) { Console.WriteLine("{0}->DoAsync.await之前", Thread.CurrentThread.ManagedThreadId.ToString());//輸出呼叫執行緒ID await Task.Run(() => Thread.Sleep(times));///執行一個非同步任務,並等待返回結果才繼續;需要注意的是,呼叫執行緒執行到這一行的時候其實就已經返回了 Console.WriteLine("{0}->DoAsync.await之後", Thread.CurrentThread.ManagedThreadId.ToString());//非同步操作執行完了,但這裡已經是新的執行緒了 } }

1->Main.非同步方法執行前
1->DoAsync.await之前
3->DoAsync.await之後
1->Main.非同步方法執行後
請留意非同步方法DoAsync的處理,在await之前和await之後,已經是兩個不一樣的執行緒ID。

也就是說,一個方法內部被拆分成了多個部分,不同的部分分別由不同的執行緒處理。

有返回值的非同步呼叫

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("{0}->Main.非同步方法執行前", Thread.CurrentThread.ManagedThreadId.ToString());//輸出非同步處理之前的執行緒ID
        var asyncTask = DoAsync(1000);//非同步執行處理
        Console.WriteLine("{0}->Main.非同步方法執行後", Thread.CurrentThread.ManagedThreadId.ToString());//輸出非同步處理之後的執行緒ID
        var result = asyncTask.Result;//等待非同步處理完成才繼續
        Console.WriteLine("{0}->Main.非同步方法完成後", Thread.CurrentThread.ManagedThreadId.ToString());//輸出非同步完成之後的執行緒ID

        Console.Read();
    }

    /// <summary>
    /// 執行非同步處理
    /// </summary>
    /// <param name="times">模擬處理時長</param>
    /// <returns></returns>
    public static async Task<int> DoAsync(int times)
    {
        Console.WriteLine("{0}->DoAsync.await之前", Thread.CurrentThread.ManagedThreadId.ToString());//輸出呼叫執行緒ID
        var result = await Task.Run(() => { Thread.Sleep(times); return times; });///執行一個非同步任務,並等待返回結果才繼續;需要注意的是,呼叫執行緒執行到這一行的時候就已經返回了
        Console.WriteLine("{0}->DoAsync.await之後", Thread.CurrentThread.ManagedThreadId.ToString());//非同步操作執行完了,但這裡已經是新的執行緒了
        return result;//返回計算結果,注意:返回結果時和進入方法時的執行緒已經不一樣了
    }
}

1->Main.非同步方法執行前
1->DoAsync.await之前
1->Main.非同步方法執行sql語句
3->DoAsync.await之後
1->Main.非同步方法完成後
請注意:在同步方法Main中執行的時候都是同一個執行緒;在非同步方法DoAsync執行的時候,在await之前是呼叫執行緒,在await之後則是另一個執行緒。

總結
在非同步(async)方法執行中,會根據await關鍵字,拆分一個方法為多個部分,分別由不同的執行緒執行。

在非同步(async)方法執行中,遇到await關鍵字,呼叫執行緒會立即返回(執行緒池)繼續後續的處理邏輯;而後,呼叫方可以使用Task.Wait()或Task.Result進行阻塞,等待非同步方法執行完畢再繼續。

在非同步(async)方法執行後,若不使用Task.Wait()進行等待,或不使用Task.Result獲取返回結果,則該方法將僅以非同步方式執行。

那麼非同步方法的好處到底在哪?一下子,我也說不上來。。因為好像只用Task,也可以達到類似的效果,雖然也有區別。

難道,非同步只是一顆語法糖嗎?規範了非同步方法的寫法,回撥函式也“消失”了。

其中非同步方法最令人意外的,大概就是呼叫執行緒遇到await關鍵字,不用等待方法執行完畢就已經立即返回了吧!

同步夾雜著非同步,非同步夾雜著任務,非同步c#教程
方法裡再拆分執行緒處理。想用好非同步不容易!