与其他.Net异步模式和类型进行互操作
返回该系列目录《基于Task的异步模式--全面介绍》
Tasks和异步编程模型APM(Tasks and the Asynchronous Programming Model)
从APM到Tasks
APM模式依赖两个对应的方法来表示一个异步操作:BeginMethodName和EndMethodName。在高级别,begin方法接受的参数和相应的同步方法MethodName的参数是一样的,而且还接受一个AsyncCallback和一个object state。begin方法然后返回IAsyncResult,IAsyncResult从它的AsyncState属性返回传递给begin方法的object state。异步操作完成时,IAsyncResult的IsCompleted属性会开始返回true,且会设置它的AsyncWaitHandle属性。而且,如果begin方法的AsyncCallback参数是非空的,那么会调用callback,且将它传给从begin方法返回的相同的IAsyncResult。当异步操作确实完成时,会使用EndMethodName方法连接该操作,检索任何结果或者强制产生的异常传播。
由于APM模式结构的本质,构建一个APM的包装器来将它暴露为一个TAP实现是相当容易的。实际上,.Net Framework 4 以TaskFactory.FromAsync的形式提供了转化的帮助路线。
思考.Net 中的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);
利用FromAsycn,可实现该方法的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); }
这个使用了FromAsync的实现和下面的具有同样效果:
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; }
从Tasks到APM
对于现有的基础设施期望代码实现APM模式的场合,能够采取TAP实现以及在期待TAP实现的地方使用它也是很重要的。幸好有了tasks的组合性,以及Task本身实现IAsyncResult的事实,使用一个简单的帮助函数就可以实现了(这里展示的是一个Task<TResult>的扩展,但几乎相同的函数可能用于非泛型的Task):
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();else tcs.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);
可以通过下面代码实现:
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; }
Tasks和基于事件的异步模式EAP(Event-based Asynchronous Pattern)
基于事件的异步模式依赖于一个返回void的实例MethodNameAsync方法,接收和同步方法MethodName方法相同的参数,并且要实例化异步操作。实例异步操作之前,事件句柄使用相同实例上的事件注册,然后触发这些事件来提供进度和完成通知。事件句柄一般都是自定义的委托类型,该委托类型利用了派生自ProgressChangedEventArgs或AsyncCompletedEventArgs的事件参数类型。
包装一个EAP实现更复杂一些,因为该模式本身牵扯了比APM模式更多的变量和更少的结构。为了演示,接下来包装一个DownloadStringAsync方法。DownloadStringAsync接受一个Uri参数,为了上报多个进度上的统计数据,下载时会触发DownloadProgressChanged 事件,完成时会触发DownloadStringCompleted 事件。最终结果是一个包含在指定Uri的页面内容的字符串。
public static Task<string> DownloadStringAsync(Uri url) {var tcs = new TaskCompletionSource<string>();var wc = new WebClient();wc.DownloadStringCompleted += (s,e) =>{if (e.Error != null) tcs.TrySetException(e.Error);else if (e.Cancelled) tcs.TrySetCanceled();else tcs.TrySetResult(e.Result);};wc.DownloadStringAsync(url);return tcs.Task; }
Tasks和等待句柄(WaitHandlers)
从WaitHandlers到Tasks
高级的开发人员可能会发现,WaitHandle 设置时,自己利用 WaitHandles 和线程池的 RegisterWaitForSingleObject 方法进行异步通知,然而这本质上不是一个异步模式 。我们可以包装RegisterWaitForSingleObject来启用WaitHandle之上的任何异步等待的基于task的选择:
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(_ => rwh.Unregister(null));return t; }
使用那些之前演示的构建于Task之上的数据结构的技巧,相似地,构建一个不依赖WaitHandles且完全以Task的角度工作的异步信号灯(semaphore)也是可能的。事实上,.Net 4.5中的SemaphoreSlim 类型暴露了开启这个的WaitAsync方法。
比如,之前提到的System.Threading.Tasks.Dataflow.dll中的BufferBlock<T>类型可以这样使用:
static SemaphoreSlim m_throttle = new SemaphoreSlim(N, N);static async Task DoOperation() {await m_throttle.WaitAsync();… // do work m_throttle.Release (); }
从Tasks到WaitHandlers
如之前提到的,Task类实现了IAsyncResult,该IAsyncResult的实现暴露了一个返回WaitHandle的AsycnWaitHandle属性,此WaitHandle是在Task完成时设置的。照这样,获得一个Task的WaitHandle可以像下面这样实现:
WaitHandle wh = ((IAsyncResult)task).AsyncWaitHandle;
返回该系列目录《基于Task的异步模式--全面介绍》
与其他.Net异步模式和类型进行互操作相关推荐
- Winsock异步模式I/O模型WSAEventSelect的使用
1.Winsock同步阻塞方式的问题 在异步非阻塞模式下,像accept(WSAAccept),recv(recv,WSARecv,WSARecvFrom)等这样的winsock函数调用后马上返回,而 ...
- 【嵌入式开发】时钟初始化 ( 时钟相关概念 | 嵌入式时钟体系 | Lock Time | 分频参数设置 | CPU 异步模式设置 | APLL MPLL 时钟频率设置 )
文章目录 一. 时钟相关概念解析 1. 相关概念术语 ( 1 ) 时钟脉冲信号 ( 概念 : 电压幅度 时间间隔 形成脉冲 | 作用 : 时序逻辑基础 间隔固定 根据脉冲数量可计算出时间 ) ( 2 ...
- 基于事件的异步模式——BackgroundWorker
转自strangeman原文 基于事件的异步模式--BackgroundWorker 实现异步处理的方法很多,经常用的有基于委托的方式,今天记录的是基于事件的异步模式.利用BackgroundWork ...
- C# 基于事件的异步模式
点击蓝字 关注我们 开工大吉 EventBasedAsyncPattern 方法使用了基于事件的异步模式.这个模式定义了一个带有 "Async" 后缀的方法.示例代码再次使用了We ...
- 高效的半同步/半异步模式的实现
先介绍一下半同步/半异步模式: 首先半同步/半异步模式中的同步和异步和前面的IO模型中的同步和异步是完全不用的概念.在IO模型中,同步和异步区分的是内核向应用程序通知的是何种IO事件(是就绪事件还是完 ...
- 半同步半异步模式 -------一个架构模式,清晰的结构,高效并发的I/O
译者: cuichaox@gmail.com 英文原文: http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf http://www.cs.wustl.edu/ ...
- Winsock的异步模式的I/O模型
Winsock的异步模式的I/O模型 闲的没事看了下Winsock的异步模式的I/O模型,写些体会和感悟,记录一下. 1.Winsock同步阻塞方式的问题1 C0 l/ W8 {2 k 在异步非阻塞模 ...
- boost::asio异步模式的C/S客户端源码实现
异步模式的服务器源码 //g++ -g async_tcp_server.cpp -o async_tcp_server -lboost_system //#include <iostream& ...
- Linux下同步模式、异步模式、阻塞调用、非阻塞调用总结
同步和异步:与消息的通知机制有关. 本质区别 现实例子 同步模式 由处理消息者自己去等待消息是否被触发 我去银行办理业务,选择排队等,排到头了就办理. 异步模式 由触发机制来通知处理消息者 我去银行办 ...
最新文章
- 数据采集技术python网络爬虫项目化教程_数据采集技术Python网络爬虫项目化教程 黄锐军课程资源.zip-KC17.pptx...
- android 启动过程
- 【poj2983】 Is the Information Reliable?
- 素数环(nyoj488)
- PetaPoco源代码学习--2.TableInfo、ColumnInfo类和Cache类
- 新能源行业SCM供应链管理平台构建一站式新能源供应链交易闭环
- [UE4] Spawn Emitter Attached 特效消失的问题的解决方法:ParticleSystem 必须附着在角色的 Mesh 上
- 怎么在局域网中设置共享文件夹?
- oracle建表默认now,oracle建表脚本当中使用默认值_oracle
- SQLExpress数据库类型与AttachDbFilename用法
- Java的getbytes()方法使用
- ValueError: matmul: Input operand 1 does not have enough dimensions (has 0, gufunc core with ...)
- 电子计算机断层扫描简称,计算机断层扫描技术(简称PET)
- H3C 交换机web页
- Aircrack-ng套件——无线破解原理及工具详解
- 赵鑫:简单技术指标的高明运用
- python数据分析算法调用_python数据分析算法(决策树2)CART算法
- 阿里前端工程师面试题+解题思路
- iDo网站在线设计系统
- Java按照章节分割大型小说文档
热门文章
- android listview ontouchlistener,Android ListView监听滑动事件的方法(详解)
- Django学习笔记《一》初始化pycharm和mysql数据库及相关环境
- linux操作系统之信号量、互斥量在进程间的同步、文件锁
- c++中的map容器
- c++中的继承--1(引出,继承方式,继承的对象模型)
- (C语言版)栈和队列(一)——实现链式栈和链式队列的基本操作以及遇到的问题
- Unity(一)必然事件
- Linux编译程序时加-I指定头文件位置
- 【电路原理】学习笔记(1):电路模型的基本变量
- Java面试2021,java黑马百度云