C#异步有多少种实现方式?

本文涉及的产品
云拨测,每月3000次拨测额度
简介: C#异步有多少种实现方式?

前言

  微信群里的一个提问引发的这个问题,有同学问:C#异步有多少种实现方式?想要知道C#异步有多少种实现方式,首先我们要知道.NET提供的执行异步操作的三种模式,然后再去了解C#异步实现的方式。

.NET异步编程模式

.NET 提供了执行异步操作的三种模式:

  • 基于任务的异步模式 (TAP) ,该模式使用单一方法表示异步操作的开始和完成。 TAP 是在 .NET Framework 4 中引入的。 这是在 .NET 中进行异步编程的推荐方法。 C# 中的 asyncawait 关键词以及 Visual Basic 中的 AsyncAwait 运算符为 TAP 添加了语言支持。 有关详细信息,请参阅基于任务的异步模式 (TAP)
  • 基于事件的异步模式 (EAP),是提供异步行为的基于事件的旧模型。 这种模式需要后缀为 Async 的方法,以及一个或多个事件、事件处理程序委托类型和 EventArg 派生类型。 EAP 是在 .NET Framework 2.0 中引入的。 建议新开发中不再使用这种模式。 有关详细信息,请参阅基于事件的异步模式 (EAP)
  • 异步编程模型 (APM) 模式(也称为 IAsyncResult 模式),这是使用 IAsyncResult 接口提供异步行为的旧模型。 在这种模式下,同步操作需要 BeginEnd 方法(例如,BeginWriteEndWrite以实现异步写入操作)。 不建议新的开发使用此模式。 有关详细信息,请参阅异步编程模型 (APM)

C#异步有四种实现方式


1、异步方法(Async Method TAP模式

使用async/await关键字实现异步编程,这是比较常用的一种异步实现方式。例如:

publicasync Task TestDoSomeAsync()

   {

       await Task.Delay(1000*10);

       Console.WriteLine("Async method completed.");

   }

2、任务并行库(TPL, Task Parallel Library TAP模式

通过 Task 和 Task<T> 类型实现异步编程,可以利用多核处理器,并发执行多个独立的任务。例如:

publicstaticvoid 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.");

               return20;// 返回一个整数值

           });


           //等待所有任务完成

           Task.WaitAll(task1, task2, task3);

       }

3、Asynchronous Programming Model(APM模式)

是一种经典的异步编程模式,需要手动创建回调函数,用于处理完成或错误的通知。可以通过 IAsyncResult 设计模式的 Begin 和 End 方法来实现,其中 Begin 方法开始异步操作,而 End 方法在异步操作完成时执行,并返回异步操作的结果。

需要注意的是,APM 模式通过 IAsyncResult 接口来存储异步操作的状态和结果,相对比较复杂,代码量也较大。同时,在使用 APM 模式时,还需要手动处理回调函数和等待异步操作完成等细节工作,使得开发起来相对较为繁琐。

class Program

   {

       staticvoid Main(string[] args)

       {

           // 创建异步操作类实例

           MyAsyncClass asyncClass = new MyAsyncClass();


           // 开始异步操作

           IAsyncResult result = asyncClass.BeginDoWork(null, null);


           // 主线程执行其他操作

           // 等待异步操作完成并获取结果

           int res = asyncClass.EndDoWork(result);


           // 处理异步操作的结果

           Console.WriteLine("Result: " + res);


           Console.ReadLine();

       }

   }


   class MyAsyncClass

   {

       ///<summary>

       /// 异步执行的方法

       ///</summary>

       ///<param name="callback">callback</param>

       ///<param name="state">state</param>

       ///<returns></returns>

       public IAsyncResult BeginDoWork(AsyncCallback callback, object state)

       {

           // 创建一个新的异步操作对象

           MyAsyncResult result = new MyAsyncResult(state);


           // 开始异步操作

           Thread thread = new Thread(() =>

           {

               try

               {

                   // 执行一些操作

                   int res = 1 + 2;


                   // 设置异步操作的结果

                   result.Result = res;


                   // 触发回调函数

                   callback?.Invoke(result);

               }

               catch (Exception ex)

               {

                   // 设置异步操作的异常

                   result.Error = ex;


                   // 触发回调函数

                   callback?.Invoke(result);

               }


           });

           thread.Start();


           // 返回异步操作对象

           return result;

       }


       ///<summary>

       /// 结束异步执行的方法

       ///</summary>

       ///<param name="result">result</param>

       ///<returns></returns>

       publicint EndDoWork(IAsyncResult result)

       {

           // 将 IAsyncResult 转换为 MyAsyncResult 类型,并等待异步操作完成

           MyAsyncResult myResult = (MyAsyncResult)result;

           myResult.AsyncWaitHandle.WaitOne();


           // 在异步操作中抛出异常

           if (myResult.Error != null)

           {

               throw myResult.Error;

           }


           // 返回异步操作的结果

           return myResult.Result;

       }

   }


   class MyAsyncResult : IAsyncResult

   {

       publicbool IsCompleted => AsyncWaitHandle.WaitOne(0);

       public WaitHandle AsyncWaitHandle { get; } = new ManualResetEvent(false);

       publicobject AsyncState { get; }

       publicbool CompletedSynchronously => false;


       publicint Result { get; set; }


       ///<summary>

       /// 存储异步操作的结果或异常信息

       ///</summary>

       public Exception Error { get; set; }


       ///<summary>

       /// 构造函数

       ///</summary>

       ///<param name="asyncState">asyncState</param>

       public MyAsyncResult(object asyncState)

       {

           AsyncState = asyncState;

       }

   }

4、Event-based Asynchronous Pattern(EAP模式)

一种已过时的异步编程模式,需要使用事件来实现异步编程。例如:

需要注意的是,EAP 模式通过事件来实现异步编程,相对于 APM 模式更加简洁易懂,同时也避免了手动处理回调函数等细节工作。但是,EAP 模式并不支持 async/await 异步关键字,因此在一些特定的场景下可能不够灵活。

publicclass MyAsyncClass : Component

   {

       ///<summary>

       /// 声明一个委托类型,用于定义异步操作的方法签名

       ///</summary>

       ///<param name="arg"></param>

       ///<returns></returns>

       publicdelegateint MyAsyncDelegate(int arg);


       ///<summary>

       /// 声明一个事件,用于通知异步操作的完成

       ///</summary>

       publicevent MyAsyncDelegate OperationNameCompleted;


       ///<summary>

       /// 异步执行方法,接受一个参数 arg

       ///</summary>

       ///<param name="arg"></param>

       publicvoid DoWorkAsync(int arg)

       {

           // 将异步操作放入线程池中执行

           ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), arg);

       }


       ///<summary>

       /// 真正的异步操作

       ///</summary>

       ///<param name="obj"></param>

       privatevoid DoWork(object obj)

       {

           int arg = (int)obj;

           int res = arg + 1;


           // 触发事件,传递异步操作的结果

           OperationNameCompleted?.Invoke(res);

       }

   }

参考文章

https://learn.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/

相关文章
|
4月前
|
编译器 数据处理 C#
C#中的异步流:使用IAsyncEnumerable<T>和await foreach实现异步数据迭代
【1月更文挑战第10天】本文介绍了C#中异步流的概念,并通过使用IAsyncEnumerable<T>接口和await foreach语句,详细阐述了如何异步地迭代数据流。异步流为处理大量数据或需要流式处理数据的场景提供了一种高效且非阻塞性的方法,使得开发者能够更优雅地处理并发和数据流问题。
|
6月前
|
C#
C#异步详解
c#异步编程原理,await asnyc的使用方法
34 0
|
9月前
|
C# 开发者
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
主要类 1.NamedPipeClientStream 2.NamedPipeServerStream 解释:命名管道是一种进程间通信的方式,它允许不同进程之间在同一台机器上进行通信
459 2
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
|
10月前
|
存储 前端开发 API
C# 从做早餐看同步异步
C# 从做早餐看同步异步
41 0
c#异步多线程
c#异步多线程
57 0
|
C#
C#多线程开发-处理异步操作中的异常
C#多线程开发-处理异步操作中的异常
152 0
|
开发框架 Java .NET
C# 同步 异步 回调 状态机 async await Demo
C# 同步 异步 回调 状态机 async await Demo 我们项目的客户端和服务端通信用的是WCF,我就想,能不能用异步的方式调用WCF服务呢?或者说能不能用async await的方式调用WCF服务呢?
543 0
C# 同步 异步 回调 状态机 async await Demo
|
存储 安全 Java
C# 之 异步多线程任务相关以及概念使用介绍
C#异步多线程Task的介绍和使用,从相关关键字到使用示例,详细解析Task和TaskCompletionSource的使用方法。
466 0
C# 之 异步多线程任务相关以及概念使用介绍
|
JSON C# 数据格式
【WPF/C#】联网异步获取二进制文件(如图片)的流程
原文:【WPF/C#】联网异步获取二进制文件(如图片)的流程 步骤: 联网异步获取Json数据。 使用Json.NET工具,反序列化Json为对应的实体类,获得该实体类的对象。 从对象身上获取图片路径(实体类中定义了头像图片是string类型的文件路径)。
1298 0