https://learn.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/
概述
C# 提供三种执行异步操作的模式:
- 异步编程模型:APM,Asynchronous Programming Model
- 基于事件:EAP,Event-based Asynchronous Pattern
- 基于任务(推荐):TAP,Task-based Asynchronous Pattern
APM
异步编程模型,.Net 1.0 (2002年),最早的异步模型,基于 IAsyncResult 接口,采用 Begin/End 方法 + 回调方法的模式。
核心特点:
- 每个异步操作对应两个方法:
BeginXXX(..., AsyncCallback callback, object state)和EndXXX(IAsyncResult result)。 - 通过
BeginXXX启动异步操作,操作完成后自动调用AsyncCallback回调函数,回调中通过EndXXX获取结果。 - 依赖
IAsyncResult跟踪异步操作状态(是否完成,结果存储等)。
例如:
1 | // 对应同步方法:Read |
缺点:
- 代码分散(启动和回调分离),尤其多步异步操作时会形成回调地狱(嵌套多层回调)。
- 需要手动管理异步状态(如通过
AsyncState传递上下文)。
EAP
基于 事件 的异步模式,.Net 2.0 (2005年),为解决 APM 的回调分散问题,EAP 将异步操作封装为 XXXAsync 方法 + XXXCompleted 事件。
核心特点:
- 异步操作通过
XXXAsync方法启动(如WebClient.DownloadStringAsync)。 - 异步操作完成 / 出错时,触发
XXXCompleted事件(如DownloadStringCompleted),在事件处理器中处理结果。 - 无需手动传递状态,事件参数(如
AsyncCompletedEventArgs)会携带结果和异常信息。
例如:
1 | var client = new WebClient(); |
优点:
- 相比
APM,代码更集中(事件处理器中统一处理结果),减少嵌套。 - 自动传递上下文(如异常、取消状态),无需手动管理
IAsyncResult。
缺点:
- 仍需依赖事件和回调,多步异步操作时仍会出现 “事件嵌套”(如 “下载完成后解析,解析完成后保存” 需嵌套多个事件)。
- 不支持
try/catch直接捕获异常(需在事件参数中判断 e.Error),不符合同步代码的异常处理习惯。
TAP
基于 Task 的异步模式,.Net 4.0 (2010年),引入 Task 和 Task<TResult> 类型。