什么是異步編程呢?舉個簡單的例子:
using System.Net.Http; using System.Threading.Tasks; using static System.Console; namespace Core { class Async { static void Main() { Start(); End(); } static void Wait()=>WriteLine("waiting..."); static void End()=>WriteLine("end..."); static int Start() { WriteLine("start..."); HttpClient client = new HttpClient(); Waiting(); var result = client.GetStringAsync("https://www.visualstudio.com/"); string str = result.Result; return str.Length; } } }
上面這段代碼中,Main方法中的代碼是按照自上而下的順序執行的。網絡狀況不佳時,Start()
方法是比較耗時(注意,這里在Start
方法中調用了異步方法GetStringAsync
,但該方法在此處是以同步方式執行的,具體原因下文會進行說明),在Start()
方法執行完畢之前,整個程序處於阻塞狀態。而異步編程可以很好的解決這個問題,一句簡單的話來概括異步編程就是,程序無須按照代碼順序自上而下的執行。
async/await
C#5.0新增了async和await關鍵字,使用這兩個關鍵字可以大大簡化異步編程
使用 async 關鍵字可將方法、lambda 表達式或匿名方法標記為異步,即,方法中應該包含一個或多個await表達式,但async關鍵字本身不會創建異步操作。
public async Task Asy() { //do something... }
這里需要注意一點,若使用async關鍵字標記的方法中沒有使用await關鍵字(編譯器會給出警告但不報錯),那么該方法將會以同步方式執行。
定義異步方法的幾點要求
定義一個異步方法應滿足以下幾點:
- 使用async關鍵字來修飾方法
- 在異步方法中使用await關鍵字(不使用編譯器會給出警告但不報錯),否則異步方法會以同步方式執行
- 盡量不使用void作為返回類型,若希望異步方法返回void類型,請使用Task
- 異步方法名稱以Async結尾
- 異步方法中不能聲明使用ref或out關鍵字修飾的變量
下面定義一個異步方法StartAsync()
:
static async Task<int> StartAsync() { HttpClient client = new HttpClient(); var str = await client.GetStringAsync("https://www.visualstudio.com/"); return str.Length; }
異步方法的返回類型
- Task<T>
如果在調用匿名方法時使用了await關鍵字,且匿名方法的返回類型是Task<T>,那么我們得到的返回類型是T。若未使用await關鍵字,則返回類型是Task。未使用await,調用GetStringAsync方法時result是Task類型。
從上圖我們可以看到調用GetStringAsync方法時未使用await關鍵字,result是Task類型,我們可以通過GetType()方法來獲取result的詳細類型信息:

從上圖可以看到result的類型全名是System.Threading.Tasks.Task

從上圖我們可以看到使用await關鍵字時,result是string類型,而匿名方法GetStringAsync的返回類型是Task<string>
-
Task
如果在調用匿名方法時使用了await關鍵字,且匿名方法的返回類型是Task,那么我們得到的返回類型是void。若為使用await關鍵字,則得到的返回類型是Task。 -
void
不建議使用void作為異步方法的返回值。
因為使用Task或Task<TResult>任務作為返回值,其屬性攜帶有關其狀態和歷史記錄的信息,如任務是否完成、異步方法是否導致異常或已取消以及最終結果是什么。而await運算符可訪問這些屬性。
異步方法執行流程
