.NET 中 async 和 await
前言
C# 中的 Async 和 Await 關鍵字是異步編程的核心。使用這兩個關鍵字可以輕松創建異步方法。使用 async 關鍵字定義的異步方法簡稱“異步方法”。
異步編程
并發的一種形式,它采用furture模式或回調(callback)機制,以避免產生不必要的線程。.Net中future的類型有 Task 和 Task<Result> 。
異步編程的核心理念是異步操作:
啟動了的操作將會在一段時間后完成。
這個操作正在執行時,但不會阻塞原來的線程。
啟動了這個操作的線程后,可以繼續執行其它任務。
當操作完成時,它會通知它的future,或者調用回調函數,以便讓程序知道操作已經結束。
異步的好處
對于面向終端用戶的GUI程序,異步可以提高響應能力。
對于服務器應用:異步編程實現了可擴展。
服務器可以利用線程池填滿其可擴展性,使用異步編程后,可擴展性通常可以提供一個數量級,可以最大程度的壓榨服務器性能,提高處理能力。
async
使用 async 修飾符可以將方法、lambda表達式或匿名方法指定為異步。
async 的主要目的是,使方法內的await關鍵字生效。
//等待異步完成再執行后邊的操作,但是整個方法不會阻塞 var?result?=?await?DoSomethingAsync(); output.Result?=?result;如果使用了 Async 最好一直使用它
await
async 標記的異步方法,可以使用 await 來指定暫定點。await 運算符通知編譯器異步方法:在等待的異步過程完成后才能繼續通過該點。同時,會將控制權返回至異步方法的調用方。
async 方法在開始時以同步的方式執行。在 async 方法內部,await 關鍵字對他的參數(一個異步任務)執行一個異步等待。它首先檢查操作是否已經完成,如果完成了,就繼續運行(同步方法)。否則,他會暫停 async 方法,并返回,將控制權交給調用方,留下一個 未完成的 Task。一段時間后,操作完成,async方法再恢復運行。
用 await 語句等待一個任務完成,當該方法在 await 處暫停時,就可以捕捉上下文(context)。如果當前SynchronizationContext不為空,這個上下文就是當前SynchronizationContext。如果當前SynchronizationContext為空,則這個上下文為當前TaskScheduler。該方法會在這個上下文中繼續運行。
//此時await會捕獲當前上下文 await?DoSomethingAsync(); //....????//這里會試圖用上邊捕獲的上下文繼續執行 await?DoSomethingAsync().ConfigureAwait(false); //....?這里開始在新的線程中運行ConfigureAwait 配置 Task 的 awaiter,將延續任務封裝回原始上下文,則為True ,否則為 False。
詳情可查閱ConfigureAwait(false)資料,這里暫時不做贅述。可閱讀以下文章
原文ConfigureAwait FAQ??
https://devblogs.microsoft.com/dotnet/configureawait-faq/
譯文理解C#中的ConfigureAwait
https://www.cnblogs.com/xiaoxiaotank/p/13529413.html
異步方法異常:
異步方法異常時會返回在 Task 對象中,并將這個 Task 對象的狀態改變為“已完成”。當 await 調用該 Task 對象時,await 會獲得并(重新)拋出該異常,并保留原始的棧軌跡。
注意:
異步方法避免使用 Task.Wait 和 Task<T>.Result ,因為他們會導致死鎖。
示例:
public?async?Task<int>?GetUrlContentLengthAsync() {var?client?=?new?HttpClient();//異步執行請求,立即返回一個Task<string>,并將控制權讓出Task<string>?getStringTask?=client.GetStringAsync("https://docs.microsoft.com/dotnet");//由于異步方法未執行等待,所以可以繼續執行不依賴異步返回結果的同步方法DoIndependentWork();//掛起任務進度,并將控制權交割GetUrlContentLengthAsync方法的調用方,并返回一個Task<int>給調用方。//該任務表示將返回下載字符串長度的一個承諾//然后調用方會繼續執行,執行不依賴于GetUrlContentLengthAsync返回結果的其它工作,否則就等待。string?contents?=?await?getStringTask;return?contents.Length; }void?DoIndependentWork() {Console.WriteLine("Working..."); }await 運算符會暫停 GetUrlContentLengthAsync 方法:
在 getStringTask 完成之前,GetUrlContentLengthAsync 無法繼續。
同時,控件返回至 GetUrlContentLengthAsync 的調用方。
當 getStringTask 完成時,控件將在此繼續。
然后,await 會從 getStringTask 檢索 string 結果
如果 DoIndependentWork 依賴于異步執行的結果,則在等待 getStringTask 返回結果期間不能進行任何工作。需要改成以下寫法。
string?getStringTask?=?await?client.GetStringAsync("https://docs.microsoft.com/dotnet");構成異步方法的條件:
方法簽名要包含 async 修飾符。
按照約定,異步方法的名稱以“Async”后綴結尾。
返回類型為以下類型之一
如果你的方法有返回值,則返回 Task<Result> 的類型。
如果你的方法沒有返回值,則返回 Task 類型
方法中至少要包含一個 await 表達式,該表達式標記一個點,在該點上,直到等待的異步操作完成方法才能繼續。同時,并且將控制權返回到方法的調用方。
返回類型
await 運算符的操作數通常是以下幾種.NET類型:Task、Task<TResult>、ValueTask或VauleTask<TResult>。但是任何可等待表達式都可以是await運算符的操作數。
總結
異步可以提高響應能力。
異步不會阻塞線程
使用 async 來標記異步方法
使用 await 來指定暫停點,掛起其進度,在等待的異步過程完成后才能繼續通過該點。同時,會將控制權返回至異步方法的調用方,調用方可以繼續執行不依賴于異步返回結果的其它工作。
如果使用了 Async 最好一直使用它
異步方法避免使用 Task.Wait 和 Task<T>.Result ,因為他們會導致死鎖。
總結
以上是生活随笔為你收集整理的.NET 中 async 和 await的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .netcore 极速接入第三方登录
- 下一篇: 年轻有为的老黄2020