【微软技术栈】与其他异步模式和类型互操作

2023-11-25 18:45

本文主要是介绍【微软技术栈】与其他异步模式和类型互操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文内容

  1. 任务和异步编程模型 (APM)
  2. 任务和基于事件的异步模式 (EAP)
  3. 任务和等待句柄

.NET 中异步模式的简短历史记录:

  • .NET Framework 1.0 引进了 IAsyncResult 模式,也称为异步编程模型 (APM) 或 Begin/End 模式。
  • .NET Framework 2.0 增加了基于事件的异步模式 (EAP)。
  • .NET Framework 4 引进了基于任务的异步模式 (TAP),它取代了 APM 和 EAP,并能够轻松构建从早期模式中迁移的例程。

1、任务和异步编程模型 (APM)

1.1 从 APM 到 TAP

因为异步编程模型 (APM) 模式的结构合理,而且能够轻松生成包装,将 APM 实现公开为 TAP 实现。 .NET Framework 4 及更高版本包含采用 FromAsync 方法重载形式的帮助器例程来实现这种转换。

请考虑 Stream 类及其 BeginRead 和 EndRead 方法,它们代表与同步 Read 方法对应的 APM:

public int Read(byte[] buffer, int offset, int count)
public IAsyncResult BeginRead(byte[] buffer, int offset,int count, AsyncCallback callback,object state)
public int EndRead(IAsyncResult asyncResult)

可以使用 TaskFactory<TResult>.FromAsync 方法来实现此操作的 TAP 包装,如下所示:

public static Task<int> ReadAsync(this Stream stream,byte[] buffer, int offset,int count)
{if (stream == null)throw new ArgumentNullException("stream");return Task<int>.Factory.FromAsync(stream.BeginRead,stream.EndRead, buffer,offset, count, null);
}

此实现类似于以下内容:

 public static Task<int> ReadAsync(this Stream stream,byte [] buffer, int offset,int count){if (stream == null)throw new ArgumentNullException("stream");var tcs = new TaskCompletionSource<int>();stream.BeginRead(buffer, offset, count, iar =>{try {tcs.TrySetResult(stream.EndRead(iar));}catch(OperationCanceledException) {tcs.TrySetCanceled();}catch(Exception exc) {tcs.TrySetException(exc);}}, null);return tcs.Task;
}

1.2 从 TAP 到 APM

如果现有的基础结构需要 APM 模式,则还需要采用 TAP 实现并在需要 APM 实现的地方使用它。 由于任务可以组合,并且 Task 类实现 IAsyncResult,你可以使用一个简单的 helper 函数执行此操作。 以下代码使用 Task<TResult> 类的扩展,但可以对非泛型任务使用几乎相同的函数。

public static IAsyncResult AsApm<T>(this Task<T> task,AsyncCallback callback,object state)
{if (task == null)throw new ArgumentNullException("task");var tcs = new TaskCompletionSource<T>(state);task.ContinueWith(t =>{if (t.IsFaulted)tcs.TrySetException(t.Exception.InnerExceptions);else if (t.IsCanceled)tcs.TrySetCanceled();elsetcs.TrySetResult(t.Result);if (callback != null)callback(tcs.Task);}, TaskScheduler.Default);return tcs.Task;
}

现在,请考虑具有以下 TAP 实现的用例:

public static Task<String> DownloadStringAsync(Uri url)

并且想要提供此 APM 实现:

public IAsyncResult BeginDownloadString(Uri url,AsyncCallback callback,object state)
public string EndDownloadString(IAsyncResult asyncResult)

以下示例演示了一种向 APM 迁移的方法:

public IAsyncResult BeginDownloadString(Uri url,AsyncCallback callback,object state)
{return DownloadStringAsync(url).AsApm(callback, state);
}public string EndDownloadString(IAsyncResult asyncResult)
{return ((Task<string>)asyncResult).Result;
}

2、任务和等待句柄

2.1 从等待句柄到 TAP

虽然等待句柄不能实现异步模式,但高级开发人员可以在设置等待句柄时使用 WaitHandle 类和 ThreadPool.RegisterWaitForSingleObject 方法实现异步通知。 可以包装 RegisterWaitForSingleObject 方法以在等待句柄中启用针对任何同步等待的基于任务的替代方法:

public static Task WaitOneAsync(this WaitHandle waitHandle)
{if (waitHandle == null)throw new ArgumentNullException("waitHandle");var tcs = new TaskCompletionSource<bool>();var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,delegate { tcs.TrySetResult(true); }, null, -1, true);var t = tcs.Task;t.ContinueWith( (antecedent) => rwh.Unregister(null));return t;
}

使用此方法,可以在异步方法中使用现有 WaitHandle 实现。 例如,若要限制在任何特定时间执行的异步操作数,可以利用信号灯(System.Threading.SemaphoreSlim 对象)。 可以将并发运行的操作数目限制到 N,方法为:初始化到 N 的信号量的数目、在想要执行操作时等待信号量,并在完成操作时释放信号量 :

static int N = 3;static SemaphoreSlim m_throttle = new SemaphoreSlim(N, N);static async Task DoOperation()
{await m_throttle.WaitAsync();// do workm_throttle.Release();
}

还可以构建不依赖等待句柄就完全可以处理任务的异步信号量。 若要执行此操作,可以使用 使用基于任务的异步模式 中所述的用于在 Task。

2.2 从 TAP 到等待句柄

正如前面所述, Task 类实现 IAsyncResult,且该实现公开 IAsyncResult.AsyncWaitHandle 属性,该属性会返回在 Task 完成时设置的等待句柄。 可以获得 WaitHandle 的 Task ,如下所示:

WaitHandle wh = ((IAsyncResult)task).AsyncWaitHandle;

这篇关于【微软技术栈】与其他异步模式和类型互操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/424369

相关文章

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Pydantic中Optional 和Union类型的使用

《Pydantic中Optional和Union类型的使用》本文主要介绍了Pydantic中Optional和Union类型的使用,这两者在处理可选字段和多类型字段时尤为重要,文中通过示例代码介绍的... 目录简介Optional 类型Union 类型Optional 和 Union 的组合总结简介Pyd

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4