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 属性中获取已完成任务的状态。
参考文章: