C#异步有多少种实现方式?
Posted 追逐时光者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#异步有多少种实现方式?相关的知识,希望对你有一定的参考价值。
前言
微信群里的一个提问引发的这个问题,C#异步有多少种实现方式?首先想要知道C#异步有多少中实现方式,首先我们要知道.NET提供的执行异步操作的三种模式,然后再去了解C#异步实现的方式。
.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)。
C#异步有四种实现方式
C# 异步有多种实现方式,可归纳为以下几类:
1、异步方法(Async Method TAP模式)
使用async/await关键字实现异步编程,这是比较常用的一种异步实现方式。例如:
public async Task TestDoSomeAsync() await Task.Delay(1000); Console.WriteLine("Async method completed.");
2、任务并行库(TPL, Task Parallel Library TAP模式)
通过 Task 和 Task<T> 类型实现异步编程,可以利用多核处理器,并发执行多个独立的任务。例如:
public static async void Main(string[] args) await Task.Run(() => Console.WriteLine("Test Task 1 completed."); ); await Task.Run(() => Console.WriteLine("Test Task 2 completed."); ); // 等待所有任务完成 Task.WaitAll();
3、Asynchronous Programming Model(APM模式)
是一种经典的异步编程模式,需要手动创建回调函数,用于处理完成或错误的通知。可以通过 IAsyncResult 设计模式的 Begin 和 End 方法来实现,其中 Begin 方法开始异步操作,而 End 方法在异步操作完成时执行,并返回异步操作的结果。
需要注意的是,APM 模式通过 IAsyncResult 接口来存储异步操作的状态和结果,相对比较复杂,代码量也较大。同时,在使用 APM 模式时,还需要手动处理回调函数和等待异步操作完成等细节工作,使得开发起来相对较为繁琐。
class Program static void 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> public int 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 public bool IsCompleted => AsyncWaitHandle.WaitOne(0); public WaitHandle AsyncWaitHandle get; = new ManualResetEvent(false); public object AsyncState get; public bool CompletedSynchronously => false; public int 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 异步关键字,因此在一些特定的场景下可能不够灵活。
public class MyAsyncClass : Component /// <summary> /// 声明一个委托类型,用于定义异步操作的方法签名 /// </summary> /// <param name="arg"></param> /// <returns></returns> public delegate int 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);
参考文章
https://learn.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/
作者:追逐时光者
作者简介:一个热爱编程,善于分享,喜欢学习、探索、尝试新事物,新技术的程序猿。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果该篇文章对您有帮助的话,可以点一下右下角的【♥推荐♥】,希望能够持续的为大家带来好的技术文章,文中可能存在描述不正确或错误的地方,欢迎指正、补充,不胜感激 !
C#异步编程
1.在系统中,每一个程序启动时,系统会分配一个进程,用以调度系统和CPU资源。而线程则是进程真正的内核。一般来说,一个进程有一个线程,但是可以通过异步编程来实现多线程编程,提高程序运行效率。
比如在程序运行中,可以使用异步编程来处理UI响应,这样程序就不必等待UI加载时间,直接进入交互逻辑运算,UI则开辟新线程来处理。实现程序的同步处理。
2. 基础的异步编程可由委托来实现。
委托实现的异步编程有三种方法,第一个是在当前线程中开辟新线程处理,并等待处理结果,再进行接下来的运算。这是最简单的异步编程,但本质上和单线程没什么区别。
第二种方法则是,开启新线程后,继续处理接下来的任务,在当前线程中定期查询异步编程是否完成,完成后再处理返回的数据结果。
第三种方法则是在开辟新线程后,完全不管新线程的进行,只是提前写好处理代码,把其委托传入新线程,系统会在新线程完成后自动回调处理方法
3. 具体代码。
第二种方法:
分析这段代码。
基础异步编程是靠委托来实现的。
每一个委托变量都有BeginInvoke和EndInvoke这两个方法。
Begin方法的作用是在系统线程池中开辟一个新的线程,计算处理这个委托变量所包含的方法。
Begin方法有三个参数,第一个参数是所包含的方法需要的参数。在这个例子中,del所委托的Add方法有两个参数,所以第一个参数就是两个整形变量。
第二和第三个参数是是回调法所需要的,等下再说。
Begin方法会返回一个实现了接口IAsyncResult的对象的引用。这个对象实现了接口的两个成员,AsyncState和IsCompleted。AsyncState是回调法用到的,Iscompleted就是这个例子中用到的变量,它是一个bool类型的值,表示新线程中的方法是否完成,当值为false的时候,就表示还没有完成。
所以循查法就是不停检测新线程是否完成,如果完成就获取返回结果,没有就继续其他代码的执行。
End方法的作用有两个,一个是返回新线程的处理结果,第二个是清除新线程的资源,节省CPU的资源。
回调法,代码如下:
在回调法中也是用委托的Begin方法来开辟新线程的,而不同点在于,回调法不需要在原来的线程中查询新线程的有关信息,而是在开辟新线程的时候,就把对结果的处理方法传进新线程,这样新线程的计算完成后,就会自动处理结果并消除线程。
传进处理方法也是通过委托实现,在Begin方法中,以第二个参数传进去。
处理方法的委托必须为AsyncResult类型的委托。AsyncResult类型的委托返回值必须为void,接受的参数必须为实现IAsyncResult的变量。Begin方法的第三个参数则是一个Object类的变量,它的作用是把处理方法需要的使用到的类传进去。比如需要把处理结果返回到主线程的一个变量中,则需要在创建新线程的时候,把这个变量传入Begin方法中。
IAsyncResult接口的另一个成员,AsyncState就是接受Begin方法传进来的那个变量。不过,一般来讲,第三个参数是把新线程的委托传进来,不然就无法在处理方法中对新线程中的处理结果进行操作了。
以上是关于C#异步有多少种实现方式?的主要内容,如果未能解决你的问题,请参考以下文章