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