前言
await與async是C#5.0推出的新語法,關于await與async有很多文章講解,但看完后有沒有這樣一種感覺,感覺這東西像是不錯,但好像就是看不太懂,也不清楚該怎么使用,雖然偶有接觸,但是一直都沒有真正搞明白,
我也是才剛剛摸索明白,把學習結果和大家探討一下看掌握得對不對,個人的學習習慣就是,有復雜的東西可以簡單說明白,就會分享出來~
(閱讀本文需要具備多執行緒及任務編程的基礎)
重點
在學習async/await最難的是什么呢?就是理解它的作業方式!
1.所有的async方法回傳型別必然是Task或Task<T>,這是異步處理的基礎!
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.異步方法執行后3->DoAsync.await之后1->Main.異步方法完成后
請注意:在同步方法Main中執行的時候都是同一個執行緒;在異步方法DoAsync執行的時候,在await之前是呼叫執行緒,在await之后則是另一個執行緒,
總結
在異步(async)方法執行中,會根據await關鍵字,拆分一個方法為多個部分,分別由不同的執行緒執行,
在異步(async)方法執行中,遇到await關鍵字,呼叫執行緒會立即回傳(執行緒池)繼續后續的處理邏輯;而后,呼叫方可以使用Task.Wait()或Task<T>.Result進行阻塞,等待異步方法執行完畢再繼續,
在異步(async)方法執行后,若不使用Task.Wait()進行等待,或不使用Task<T>.Result獲取回傳結果,則該方法將僅以異步方式執行,
那么異步方法的好處到底在哪?一下子,我也說不上來,,因為好像只用Task,也可以達到類似的效果,雖然也有區別,
難道,異步只是一顆語法糖嗎?規范了異步方法的寫法,回呼函式也“消失”了,
其中異步方法最令人意外的,大概就是呼叫執行緒遇到await關鍵字,不用等待方法執行完畢就已經立即回傳了吧!
同步夾雜著異步,異步夾雜著任務,異步方法里再拆分執行緒處理,想用好異步不容易!
參考
C#語法——await與async的正確打開方式
為什么我們要使用Async、Await關鍵字
async & await 的前世今生(Updated)
異步編程 In .NET
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/80527.html
標籤:C#
上一篇:ADO.NET事務封裝
下一篇:.Net 面試題整理(一)
