本文是.NET異步和多線程系列的第六章,本章主要對以前介紹過的async/await作一些補充說明。html
下面咱們直接來看下代碼和運行結果:多線程
using System; using System.Threading; using System.Threading.Tasks; namespace MyAsyncAwait { /// <summary> /// await/async 是C#保留關鍵字,一般是成對出現,語法糖。 /// /// 主線程調用async/await方法,主線程遇到await返回執行後續動做, /// await後面的代碼會等着Task任務的完成後再繼續執行 /// 其實就像把await後面的代碼包裝成一個ContinueWith的回調動做 /// 而後這個回調動做多是Task線程,也多是新的子線程,也多是主線程 /// /// 一個async方法,若是沒有返回值,能夠方法聲明返回Task /// await/async可以用同步的方式編寫代碼,但又是非阻塞的。 /// /// async方法在編譯後會生成一個狀態機(實現了IAsyncStateMachine接口) /// </summary> class Program { static void Main(string[] args) { Console.WriteLine($"當前主線程開始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); AwaitAsyncClass.TestShow(); Console.WriteLine($"當前主線程結束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Console.ReadKey(); } } /// <summary> /// await/async關鍵字 語法糖 /// await/async 要麼不用 要麼用到底 /// </summary> public class AwaitAsyncClass { public static void TestShow() { Test(); } private async static Task Test() { Console.WriteLine($"Test開始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Task<long> t = SumAsync(); Console.WriteLine($"遇到await主線程回來幹活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); { long lResult = await t; //await後面的代碼會由線程池的線程執行,非阻塞。 Console.WriteLine($"最終獲得的lResult={lResult}"); } { //t.Wait(); //主線程等待Task的完成,阻塞的 //long lResult = t.Result; //訪問Result,主線程等待Task的完成,阻塞的,效果跟t.Wait()同樣 //Console.WriteLine($"最終獲得的lResult={lResult}"); } Console.WriteLine($"Test結束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); } /// <summary> /// 帶返回值的Task /// 要使用返回值就必定要等子線程計算完畢 /// </summary> private static async Task<long> SumAsync() { Console.WriteLine($"SumAsync start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); long result = 0; //await後面的代碼會等着Task任務的完成後再繼續執行 //其實就像把await後面的代碼包裝成一個ContinueWith的回調動做 //而後這個回調動做多是Task線程,也多是新的子線程,也多是主線程 await Task.Run(() => { for (int k = 0; k < 2; k++) { Console.WriteLine($"SumAsync 第1個 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumAsync 第1個 await Task.Run的後續任務開始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); await Task.Run(() => { for (int k = 0; k < 2; k++) { Console.WriteLine($"SumAsync 第2個 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumAsync 第2個 await Task.Run的後續任務開始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); await Task.Run(() => { for (int k = 0; k < 2; k++) { Console.WriteLine($"SumAsync 第3個 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumAsync end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return result; } } }
運行結果以下:異步
仔細觀察結果會發現:async
主線程調用async/await方法,主線程遇到await後會返回執行後續動做;spa
await後面的代碼會等着Task任務的完成後再繼續執行,其實就像把await後面的代碼包裝成一個ContinueWith的回調動做;線程
而後這個回調動做多是Task線程,也多是新的子線程,也多是主線程;code
await/async可以用同步的方式編寫代碼,但又是非阻塞的。htm
下面咱們調整下Test方法後再運行(紅色的爲調整部分):blog
private async static Task Test() { Console.WriteLine($"Test開始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Task<long> t = SumAsync(); Console.WriteLine($"遇到await主線程回來幹活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); { //long lResult = await t; //await後面的代碼會由線程池的線程執行,非阻塞。 //Console.WriteLine($"最終獲得的lResult={lResult}"); } { //t.Wait(); //主線程等待Task的完成,阻塞的 long lResult = t.Result; //訪問Result,主線程等待Task的完成,阻塞的,效果跟t.Wait()同樣 Console.WriteLine($"最終獲得的lResult={lResult}"); } Console.WriteLine($"Test結束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); }
調整後運行結果以下:接口
仔細觀察結果會發現:
訪問Result,主線程會等待Task的完成,阻塞的。
其實async方法在編譯後會生成一個狀態機(實現了IAsyncStateMachine接口),有興趣的能夠自行去了解下。
至此本文就介紹完了,有興趣的還能夠看下我以前寫過一篇也是關於async/await的文章:https://www.cnblogs.com/xyh9039/p/11391507.html
Demo源碼:
連接:https://pan.baidu.com/s/1jnG5IpteuKCdmF6-tr--cA 提取碼:3onm
此文由博主精心撰寫轉載請保留此原文連接:https://www.cnblogs.com/xyh9039/p/13622122.html