C# async 和 await 理解
先假設如下場景:
主函數 Main,循環等待用戶輸入;
計算函數 Cal,耗時計算大量數據;
class Test {static int Main(string[] args){while(true){// 等待用戶輸入}}public static int Cal() {int sum = 0;for (int i = 0; i < 999; i++){sum = sum + i;}Console.WriteLine($"sum={sum}");return sum;} }為了在Main函數中調用Cal函數,同時Cal函數不阻塞主函數的循環,此時需要考慮增加一個CalAsync函數使Cal函數異步執行。
傳統的思維方法? 在CalAsync函數中啟動一個線程,并在線程中執行Cal函數:
// using System.Threading; public static CalAsync() {Thread td = new Thread(new ThreadStart(Cal));td.start(); }這種方法顯示地創建了一個線程并啟動執行,CalAsync函數本身還是在主線程執行并且無法直接獲取Cal函數的結果。
async 和 await 異步編程方法? 使用async標記CalAsync函數,并在CalAsync函數中創建任務Task異步執行Cal函數,同時使用await標記獲取Cal函數的執行結果:
// using System.Threading.Tasks; public static aysnc void CalAsync() {int result = await Task.Run(new Func<int>(Cal));// 或使用lambda書寫方式// int result = await Task.Run(() => test());Console.WriteLine(result); }在Main函數中直接調用CalAsync函數,可以發現CalAsync成功調用了Cal函數并在一段時間后輸出了結果,同時Main函數并不會被阻塞。
分別在Main、Cal、CalAsync函數中增加代碼打印當前線程ID:
class Test {static void Main(string[] args){string tid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine($"Main1 tid {tid}");Task<int> t = CalAsync();Console.WriteLine($"Main after CalAsync");Console.Read();}public static int Cal(){string tid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine($"Cal tid {tid}");int sum = 0;for (int i = 0; i < 999; i++){sum = sum + i;}Console.WriteLine($"sum={sum}");return sum;}public static async Task<int> CalAsync(){string tid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine($"CalAsync1 tid {tid}");int result = await Task.Run(new Func<int>(Cal));tid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine($"CalAsync2 tid {tid}, result={result}");return result;} }結果如圖:??
?
可以看出,在CalAsync函數中,await標記之前,代碼在主線程中執行,而await標記之后,代碼在子線程中執行。
理解與結論:
-
在C#中, async標記了一個包含異步執行的函數,通過async標記的函數若在主線程中直接調用,則函數一開始仍在主線程中執行;
-
aysnc標記的函數內部必須包含await標記需要異步執行的函數(根據vs2017編譯提示),若當前函數在主線程中直接調用,則await標記前的代碼在主線程中執行,await標記后的代碼在其異步子線程中執行;
-
async標記的函數返回值必須為void、Task、Task< TResult> 類型,可以理解為async標記的函數返回的是 “空”、“即將執行的任務”、“帶結果的即將執行的任務”實例;
-
async標記的函數可以繼續往下調用async標記函數,調用形式如下例, 從調用邏輯可以理解為await實際上用來觸發所標記的Task任務異步執行,并最后獲取異步執行的返回值,從運行過程看該觸發應該僅對最終的Task任務有效:
?
?
總結
C#中async與await異步編程,可以理解為:
1. async聲明了一個包含異步執行代碼的函數,該函數執行時不會阻塞調用線程;
2. await存在于async函數中,聲明了一個異步執行入口,程序動態運行時從該入口創建并進入一個異步線程環境,并在該線程執行任務實例及任務實例返回之后的代碼;
3. 一個async函數中聲明多個await關鍵字時,程序將代碼順序創建并進入異步子線程執行任務實例及任務實例返回之后的代碼直到下一個await聲明處, 最后一個await聲明之后的代碼會在最后一個異步子線程中執行 ;
3. await標記的右側代碼返回或定義了一個任務實例,該實例由需要異步執行的目標耗時函數初始化,并在最終定義處觸發異步執行。
總結
以上是生活随笔為你收集整理的C# async 和 await 理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利率可超5%的结构性存款,与利率在4%左
- 下一篇: 国产电动车高端玩家 2022款蔚来ES8