1. 程式人生 > >aync await 進一步探索

aync await 進一步探索

ilo 告訴 csg sync 編譯不過 weight method pic 異步調用

aync await 進一步探索

首先來個例子

class Program
{
static int index = 1;
static void Log(string str)
{
Console.WriteLine((index++) + ". " + str + ". ThreadId:" + Thread.CurrentThread.ManagedThreadId);
}

        static void Main(string[] args)
        {
            //解決.net core控制臺輸出中文亂碼的代碼
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            //async 不能用於Main方法,所以在這裏單獨使用一個方法來調用,各位可以試試,編譯不過,但VS就是不會告訴你錯誤在哪裏
            ExcuteAsync(); 
            Console.ReadLine();
        }

        static async void ExcuteAsync() {
            Log("異步方法調用前");
            var ret = AsyncMethod();
            Log("異步方法調用後");
            Log(await ret);
            Log("異步方法使用await後");
        }

        static async Task<string> AsyncMethod() {
            Log("異步方法開始");
            var task = Task.Run<string>(() =>
            {
                Log("異步方法內部開始");
                Thread.Sleep(3000);
                Log("異步方法內部結束");
                return "來自異步方法內部的結果";
            });
            Log("異步方法結束");
            var ret = await task;
            Log("異步方法await結束");
            return ret;
        }
    }

控制臺輸出結果

1. 異步方法調用前. ThreadId:1
2. 異步方法開始. ThreadId:1
3. 異步方法結束. ThreadId:1
4. 異步方法內部開始. ThreadId:3
5. 異步方法調用後. ThreadId:1
6. 異步方法內部結束. ThreadId:3
7. 異步方法await結束. ThreadId:3
8. 來自異步方法內部的結果. ThreadId:3
9. 異步方法使用await後. ThreadId:3

分析

為了描述更方便,為每條輸出都添加了序號。 為了更清晰的知道每一步的執行順序以及所在的線程,均添加了ThreadId

  1. 第1條輸出,主線程,沒有什麽特別的。
  2. 第2條輸出,主線程,說明:調用異步方法本身並不會另起一個線程,如果這裏面沒有await的話,調用這個方法和調用普通方法沒有任何區別。
  3. 第3條輸出,主線程,說明:執行異步方法後主線程並沒有被掛起,而是直接繼續往下走。
  4. 第4條輸出,線程3(代表子線程,不一定每次都是3),代碼顯示的要起用一個新線程,沒有什麽特別的。
  5. 第5條輸出,主線程,和第3條一樣,主線程繼續往下走,只是代碼在不同的方法裏而已。
  6. 第6條輸出,線程3,內部執行結束,沒什麽特別。
  7. 第7條輸出,線程3,說明:這裏有一個不同的地方,使用了await,可見,這裏是子線程的延續
  8. 第8-9條輸出,線程3,和第7條一樣,延續了子線程。

變種

我們把ExcuteAsync方法裏的await ret,改成ret.Result看看效果

1. 異步方法調用前. ThreadId:1
2. 異步方法開始. ThreadId:1
3. 異步方法結束. ThreadId:1
4. 異步方法內部開始. ThreadId:3
5. 異步方法調用後. ThreadId:1
6. 異步方法內部結束. ThreadId:3
7. 異步方法await結束. ThreadId:3
8. 來自異步方法內部的結果. ThreadId:1
9. 異步方法使用await後. ThreadId:1

第8-9條輸出線程變了,可見是主線程被掛起了,等待子線程結束後繼續往下執行。那麽如果在AsyncMethod裏也使用Result,效果又是什麽樣的?

我們把AsyncMethod方法裏的await task改成task.Result,看輸出結果

1. 異步方法調用前. ThreadId:1
2. 異步方法開始. ThreadId:1
3. 異步方法結束. ThreadId:1
4. 異步方法內部開始. ThreadId:3
5. 異步方法內部結束. ThreadId:3
6. 異步方法await結束. ThreadId:1
7. 異步方法調用後. ThreadId:1
8. 來自異步方法內部的結果. ThreadId:1
9. 異步方法使用await後. ThreadId:1

現在只有Task內部的輸出是在子線程了。可見,使用Result的話會失去異步的效果,換句話說,使用Result就不再是異步調用了

附:文筆不好,只能用習慣的代碼來描述,希望能給讀者帶來幫助。

?

aync await 進一步探索