C# 5.0 推出async和await,最先是.NET Framework 4.5引入,能夠在Visual Studio 2012使用。在此以前的異步編程實現難度較高,async使異步編程的實現變得簡便。編程
平臺 | async |
---|---|
.NET 4.5及以上 | ✓ |
.NET 4.0 | NuGet |
Mono iOS/Droid | ✓ |
Windows Store | ✓ |
Windows Phone Apps 8.1 | ✓ |
Windows Phone SL 8.0 | ✓ |
Windows Phone SL 7.1 | NuGet |
Silverlight 5 | NuGet |
在不支持的平臺,安裝NuGet包 Microsoft.Bcl.Async數據結構
使用
async
修飾符可將方法、lambda 表達式或匿名方法指定爲異步。異步
從使用async修飾符修飾的方法的IL代碼能夠得出一個結論:async
舉例:
C#代碼以下ide
using System.Threading.Tasks; namespace ConsoleApp3 { public class Test { public async Task TestAsync() { await GetAsync(); } public async Task GetAsync() { await Task.Delay(1); } } }
以TestAsync方法爲準異步編程
Release下 初始化狀態機V_0
,類型是值類型Struct(valuetype
),類型名稱爲<TestAsync>d__0
性能
.locals init ( [0] valuetype ConsoleApp3.Test/'<TestAsync>d__0' V_0, [1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder V_1 )
<TestAsync>d__0
繼承值類型[mscorlib]System.ValueType
ui
.class nested private sealed auto ansi beforefieldinit '<TestAsync>d__0' extends [mscorlib]System.ValueType implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine
Debug 下 初始化狀態機V_0
,類型是引用類型Class(class
) ,類型名稱爲<TestAsync>d__0
this
.locals init ( [0] class ConsoleApp3.Test/'<TestAsync>d__0' V_0, [1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder V_1 )
<TestAsync>d__0
繼承引用類型[mscorlib]System.Object
spa
.class nested private sealed auto ansi beforefieldinit '<TestAsync>d__0' extends [mscorlib]System.Object implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine
使用
async
關鍵字定義的異步方法簡稱爲「異步方法」。
注意事項:
async
關鍵字修改的方法不包含 await
表達式或語句,則該方法將同步執行。 編譯器警告將通知你不包含 await
語句的任何異步方法,由於該狀況可能表示存在錯誤。 請參閱編譯器警告(等級 1)CS4014。async
關鍵字是上下文關鍵字,緣由在於只有當它修飾方法、lambda 表達式或匿名方法時,它纔是關鍵字。 在全部其餘上下文中,都會將其解釋爲標識符。void
做爲 async
方法的返回類型! async
方法能夠返回 void
,可是這僅限於編寫事件處理程序。一個普通的 async
方法若是沒有返回值,要返回Task
,而不是 void
。Task.Wait
或 Task<T>.Result
方法,由於它們會致使死鎖。若是使用了 async
,最好就一直使用它。out
,ref
。out
或 ref
返回的數據應借用Task<TResult>
返回,可使用元組或自定義數據結構。async
修飾符。TResult
類型的返回語句,則爲 Task<TResult>
。Task
。void
:若是要編寫異步事件處理程序。GetAwaiter
方法的其餘任何類型(自 C# 7.0 起)。關於async和await具體的執行流程,方法什麼時候掛起和釋放,請參考異步程序中的控制流 (C#)
上面提到 void
做爲返回結果,適用於事件處理程序。
舉例:
using System; using System.Threading.Tasks; namespace ConsoleApp3 { public class TestVoidAsync { private event EventHandler<EventArgs> DoTest; public TestVoidAsync() { DoTest += DoTestEvent; } private static async void DoTestEvent(object sender, EventArgs e) { await Task.Delay(1000); } protected virtual void OnDoTest() { DoTest?.Invoke(this, EventArgs.Empty); } } }
void
做爲返回結果存在一個弊端:沒法捕獲異常。
返回 void 的異步方法的調用方沒法捕獲從該方法引起的異常,且此類未經處理的異常可能會致使應用程序故障。 若是返回
Task
或Task<TResult>
的異步方法中出現異常,此異常將存儲於返回的任務中,並在等待該任務時再次引起。
通用的異步返回類型:
從 C# 7.0 開始,異步方法可返回任何具備可訪問的 GetAwaiter 方法的類型。
ValueTask<TResult>
:
Task 和 Task<TResult> 是引用類型
,所以,性能關鍵路徑中的內存分配會對性能產生負面影響,尤爲當分配出如今緊湊循環中時。 支持通用返回類型意味着可返回輕量值類型(而不是引用類型),從而避免額外的內存分配。
使用ValueTask<TResult>
,須要添加NuGet包 System.Threading.Tasks.Extensions
。
ValueTask<TResult>
是struct值類型,Task 和 Task<TResult>
是class引用類型
Task 類提供了異步操做的生命週期,且該週期由 TaskStatus 枚舉表示。
狀態 | 執行順序 | 備註 |
---|---|---|
Created | 0 | 該任務已初始化,但還沒有安排。 |
WaitingForActivation | 1 | 該任務正在等待被.NET Framework infrastructure 內部激活和調度。 |
WaitingToRun | 2 | 該任務已安排執行但還沒有開始執行。 |
Running | 3 | 任務正在運行但還沒有完成。 |
WaitingForChildrenToComplete | 4 | 任務已完成執行,並隱式等待附加的子任務完成。 |
RanToCompletion | 5 | 任務已成功完成執行。 |
Canceled | 6 | 引起 OperationCanceledException 異常,或者在任務開始執行以前取消 |
Faulted | 7 | 因爲未處理的異常,任務已完成。 |
Canceled 和 Faulted狀態都會由於任務異常致使轉換爲該狀態。兩者的區別以下:
若是標記的 IsCancellationRequested 屬性返回 false,或者異常的標記與任務的標記不匹配,則會將 OperationCanceledException 按照普通的異常來處理,從而致使任務轉換爲 Faulted 狀態。 另外還要注意,其餘異常的存在將也會致使任務轉換爲 Faulted 狀態。 您能夠在 Status 屬性中獲取已完成任務的狀態。
參考文章: