前言
想要知道.NET异步有多少种实现方式,首先我们要知道.NET提供的执行异步操作的三种模式,然后再去了解.NET异步实现的四种方式。
.NET执行异步操作的三种模式
- 基于任务的异步模式 (TAP)【推荐使用】 :该模式使用单一方法表示异步操作的开始和完成,TAP 是在 .NET Framework 4 中引入的。这是在 .NET 中进行异步编程的推荐方法。 C# 中的 async 和 await 关键词以及 Visual Basic 中的 Async 和 Await 运算符为 TAP 添加了语言支持。有关详细信息,请参阅基于任务的异步模式 (TAP)。
- 基于事件的异步模式 (EAP):是提供异步行为的基于事件的旧模型, 这种模式需要后缀为 Async 的方法,以及一个或多个事件、事件处理程序委托类型和 EventArg 派生类型。EAP 是在 .NET Framework 2.0 中引入的。建议新开发中不再使用这种模式。有关详细信息,请参阅基于事件的异步模式 (EAP)。
- 异步编程模型 (APM) 模式(也称为 IAsyncResult 模式):这是使用 IAsyncResult 接口提供异步行为的旧模型, 在这种模式下,同步操作需要 Begin 和 End 方法(例如,BeginWrite 和 EndWrite以实现异步写入操作)。不建议新的开发使用此模式。有关详细信息,请参阅异步编程模型 (APM)。
.NET异步编程有什么作用?
- 提高性能和资源利用率:异步编程可以在等待 I/O 操作完成的同时释放线程资源,使得线程能够继续执行其他任务,从而提高了系统的资源利用率和性能。
- 改善用户体验:通过异步编程,可以避免在等待长时间操作完成时出现界面卡顿或无响应的情况,从而改善用户体验,使应用程序更加流畅和响应。
- 简化编程模型:使用 C# 提供的
async
和await
关键字可以使异步编程变得更加简洁和易于理解,避免了传统的回调地狱(callback hell),使代码更具可读性和可维护性。 - 提高并发性:通过异步编程,可以更有效地处理并发请求,从而提高系统的并发性能,使得应用程序能够更好地处理大量用户请求。
- 支持大规模并行编程:异步编程模型使得在大规模并行编程中更容易管理和控制异步任务的执行,提供了更灵活的并发编程方式。
总的来说,异步编程在提高系统性能、改善用户体验、简化编程模型和支持并行编程方面发挥着重要作用,是现代软件开发中不可或缺的重要技术之一。
一、异步方法(Async Method TAP模式)
使用async/await关键字实现异步编程,这是比较常用的一种异步实现方式。例如:
/// <summary> /// 异步方法(Async Method TAP模式) /// </summary> /// <returns></returns> public static async Task TestDoSomeAsync() { await Task.Delay(1000 * 10).ConfigureAwait(false); //等待10秒 Console.WriteLine("Async Method Completed."); }
二、任务并行库(TPL, Task Parallel Library TAP模式)
通过 Task 和 Task类型实现异步编程,可以利用多核处理器,并发执行多个独立的任务。例如:
/// <summary> /// 任务并行库(TPL, Task Parallel Library TAP模式) /// </summary> public static void TestTaskParallel() { var task1 = Task.Run(() => { Console.WriteLine("Task 1 Completed."); }); var task2 = Task.Run(() => { Console.WriteLine("Task 2 Completed."); }); Task<int> task3 = Task.Factory.StartNew(() => { Console.WriteLine("Task 3 Completed."); return 20; // 返回一个整数值 }); //等待所有任务完成 Task.WaitAll(task1, task2, task3); }
三、Asynchronous Programming Model(APM模式)
是一种经典的异步编程模式,需要手动创建回调函数,用于处理完成或错误的通知。可以通过 IAsyncResult 设计模式的 Begin 和 End 方法来实现,其中 Begin 方法开始异步操作,而 End 方法在异步操作完成时执行,并返回异步操作的结果。
注意:在 .NET Core 或 .NET 5+ 等新版本中,BeginInvoke 方法已经被弃用并不再支持,因此可能会导致 System.PlatformNotSupportedException 异常,不过在.NET FX环境是支持的。
/// <summary> /// Asynchronous Programming Model(APM模式) /// </summary> public static void TestAPMAsync() { // 创建一个 AsyncCallback 委托,用于处理异步操作完成后的回调 var callback = new AsyncCallback(AsyncOperationCallback); // 创建一个异步委托实例,表示要异步执行的操作 var asyncMethod = new Func<int, string>(AsyncMethod); // 开始异步操作 var result = asyncMethod.BeginInvoke(88, callback, asyncMethod); Console.WriteLine($"TestAPMAsync Completed."); Console.ReadLine(); } private static string AsyncMethod(int parameter) { Console.WriteLine("AsyncMethod开始执行了..."); return $"异步操作完成,参数为:{parameter}。"; } private static void AsyncOperationCallback(IAsyncResult result) { try { // 从异步状态对象中获取返回的异步委托 Func<int, string> asyncMethod = (Func<int, string>)result.AsyncState; string message = asyncMethod.EndInvoke(result); Console.WriteLine(message); } catch (Exception ex) { Console.WriteLine($"异步操作发生异常:{ex.Message}"); } }
四、Event-based Asynchronous Pattern(EAP模式)
是一种已过时的异步编程模式,需要使用事件来实现异步编程。
需要注意的是,EAP 模式通过事件来实现异步编程,相对于 APM 模式更容易理解,同时也避免了手动处理回调函数等细节工作。但是,EAP 模式并不支持 async/await 异步关键字,因此在一些特定的场景下可能不够灵活。
/// <summary> /// Event-based Asynchronous Pattern(EAP模式) /// </summary> static void Main(string[] args) { var asyncObj = new MyAsyncClass(); // 订阅异步操作完成事件 asyncObj.OperationNameCompleted += AsyncObjOperationNameCompleted; // 启动异步操作 asyncObj.DoWorkAsync(10); Console.ReadLine(); } /// <summary> /// 异步操作完成事件的处理方法 /// </summary> /// <param name="result">result</param> private static void AsyncObjOperationNameCompleted(int result) { Console.WriteLine($"异步操作完成,结果为: {result}"); } public class MyAsyncClass : Component { /// <summary> /// 声明一个委托类型,用于定义异步操作的方法签名 /// </summary> /// <param name="arg"></param> /// <returns></returns> public delegate void MyAsyncDelegate(int arg); /// <summary> /// 声明一个事件,用于通知异步操作的完成 /// </summary> public event MyAsyncDelegate OperationNameCompleted; /// <summary> /// 异步执行方法,接受一个参数 arg /// </summary> /// <param name="arg"></param> public void DoWorkAsync(int arg) { // 将异步操作放入线程池中执行 ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), arg); } /// <summary> /// 真正的异步操作 /// </summary> /// <param name="obj"></param> private void DoWork(object obj) { int arg = (int)obj; int res = arg + 1; // 触发事件,传递异步操作的结果 OperationNameCompleted?.Invoke(res); } }
拾遗补漏合集
在这个快速发展的技术世界中,时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节,以帮助大家更全面地了解这些技术栈的特性和发展方向。
GitHub开源地址
https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetStudy.md
拾遗补漏知识点投稿
该Issues主要是给各位小伙伴们提供投稿的地方,你有什么想要学习的C#/.NET/.NET Core相关技术栈或者已学习过且有文章输出的欢迎在投稿!