与其他.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的异步模式--全面介绍》


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Android]AndroidBucket增加碎片SubLayout功能及AISubLayout的注解支持

以下内容为原创&#xff0c;转载请注明&#xff1a; 来自天天博客&#xff1a;http://www.cnblogs.com/tiantianbyconan/p/3709957.html 之前写过一篇博客&#xff0c;是使用Fragment来实现TabHost的效果&#xff0c;并且模拟TabHost的切换各个fragment生命周期的调用&#xff…

更新说明

按暂时的设想&#xff0c;这个 blog 近期主要会更新三个方面的内容。 其一&#xff0c;是关于 Andrew Ng 在 coursa 上开设的 Machine Learning 的课程。 我不打算放课堂的笔记或者实录&#xff0c;而是主要分析一些作业的小项目的实现思路以及一些补充性的内容。有机会的话也试…

Java设计模式6:策略模式

策略模式 策略模式的用意是针对一组算法&#xff0c;将每一个算法封装到具有共同接口的独立类中&#xff0c;从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。 策略模式的结构 策略模式是对算法的包装&#xff0c;是把使用算法的责任和算法本…

WordPress 获取当前页面 ID 的几大方法

https://zhangzifan.com/wordpress-get-id.html 在很多的 WordPress 主题或者插件功能的开发中&#xff0c;我们总是需要获取到 WordPress 给每个页面定义的 ID&#xff0c;不然也某些情况下是无法确定这是哪一个页面&#xff0c;针对于文章或者页面的 ID 获取基本可以使用 get…

王者荣耀交流协会第四次Scrum立会

拍照的是王磊同学&#xff0c;没有出镜。 开会时间&#xff1a;2017年10月30日下午18&#xff1a;45-19&#xff1a;16 共计31分钟 开会地点&#xff1a;一食堂二楼靠近窗户倒数第四排 今日完成工作进度&#xff1a; 袁玥同学完成了点击按钮刷新时间的功能代码&#xff1b; 王…

Python在信号与系统(1)——Hilbert兑换,Hilbert在国家统计局的包络检测应用,FIR_LPF滤波器设计,格鲁吉亚也迫使高FM(PM)调制...

谢谢董老师&#xff0c;董老师是个好老师。 心情久久不能平静&#xff0c;主要是高频这门课的分析方法实在是让我难以理解&#xff0c;公式也背只是&#xff0c;还是放放吧。 近期厌恶了Matlab臃肿的体积和频繁的读写对我的Mac的损害&#xff0c;所以学习了一下Python这一轻量级…

如何在WP-Config中设置WordPress错误日志

https://baijiahao.baidu.com/s?id1622279671500148245&wfrspider&forpc 你想在wp-config文件中设置WordPress错误日志吗&#xff1f;WordPress中的wp-config文件不仅控制您的WordPress网站设置&#xff0c;它也是一个非常有用的调试工具&#xff0c;可帮助您查找和修…

[再寄小读者之数学篇](2014-04-22 平方差公式在矩阵中的表达)

设 $A,B$ 都是 $n$ 阶复方阵, 且 $A^2B^22AB$. 证明: (1) $AB-BA$ 不可逆; (2) 如果 $\rank(A-B)1$, 那么 $ABBA$. 转载于:https://www.cnblogs.com/zhangzujin/p/3712973.html

C#:ref和out的联系及区别。

总结以上四条得到ref和out使用时的区别是&#xff1a;①&#xff1a;ref指定的参数在函数调用时候必须初始化&#xff0c;不能为空的引用。而out指定的参数在函数调用时候可以不初始化&#xff1b;②&#xff1a;out指定的参数在进入函数时会清空自己&#xff0c;必须在函数内部…

wordpress启用侧边栏小工具

http://www.seo628.com/1872.html wordpress后台默认不显示小工具选项&#xff0c;开发者需要启用小工具功能并把小工具在相应的前台位置调用出来&#xff0c;这样才能在后台直接拖动生成侧边栏。 激活小工具 激活小工具需要在functions.php中注册至少一个侧边栏 register_s…

comparator接口与Comparable接口的区别

Comparable & Comparator 都是用来实现集合中元素的比较、排序的&#xff0c;只是 Comparable 是在集合内部定义的方法实现的排序&#xff0c;Comparator 是在集合外部实现的排序&#xff0c;所以&#xff0c;如想实现排序&#xff0c;就需要在集合外定义 Comparator 接口的…

详解 Spotlight on MySQL监控MySQL服务器

前一章详解了Spotlight on Unix 监控Linux服务器 &#xff0c;今天再来看看Spotlight on MySQL怎么监控MySQL服务器。 注&#xff1a;http://www.cnblogs.com/Javame/p/3685512.html 第一步: 下载并安装mysql-connector-3.5x Spotlight on MySQL 连接mysql必须使用mysql-connec…

lua------------------Unity3D研究院编辑器之打开unity不可识别的文件(十三)

Unity3D研究院编辑器之打开unity不可识别的文件&#xff08;十三&#xff09; 雨松MOMO 【Unity3D拓展编辑器】 围观8597次 9 条评论 编辑日期&#xff1a;2017-03-02 字体&#xff1a;大 中 小 有些特殊后缀名的文件在unity里是不可识别的。如下图所示&#xff0c;这里我把文本…

一起Polyfill系列:Function.prototype.bind的四个阶段

昨天边参考es5-shim边自己实现Function.prototype.bind&#xff0c;发现有不少以前忽视了的地方&#xff0c;这里就作为一个小总结吧。 一、Function.prototype.bind的作用 其实它就是用来静态绑定函数执行上下文的this属性&#xff0c;并且不随函数的调用方式而变化。 示例&am…

Window 通过cmd查看端口占用、相应进程、杀死进程等的命令【转】

一、 查看所有进程占用的端口 在开始-运行-cmd,输入&#xff1a;netstat –ano可以查看所有进程 二、查看占用指定端口的程序 当你在用tomcat发布程序时&#xff0c;经常会遇到端口被占用的情况&#xff0c;我们想知道是哪个程序或进程占用了端口&#xff0c;可以用该命令 ne…

盘点18个免费的WordPress主题后台选项开发框架

https://yusi123.com/3205.html/3 13.Warp Framework Warp框架不仅支持WordPress和Joomla,还可以可扩展到其他的适用Web程序。使用Warp框架你可以轻松的定制你需要的功能。 该框架是来自Yootheme团队。看看他们出的主题&#xff0c;你就知道这个绝对是精品了。精心设计的界面和…

lua----------------使用VS2015搭建lua开发环境的一些侥幸成功经验,

所以本篇博文介绍在Windows平台下&#xff0c;使用VS2015搭建lua开发环境的一些侥幸成功经验&#xff0c;安装过程参考网上教程&#xff0c;安装过程如下&#xff08;参考http://www.byjth.com/lua/33.html&#xff09; 一 生成lua5.3.lib 1、下载并编译lua源码 首先进入lua官…

中国剩余定理求解“六位教授必须首次都停止上课”问题

问题&#xff1a; 六位教授在周一至周六开始上课&#xff0c;这六位教授分别每2,3,4,1,6,5天授课一次&#xff0c; 该学校禁止周天上课&#xff0c;因此周天必须停课&#xff0c;问什么时候所有六位教授首次发现他们必须同时停课&#xff1f;(中国剩余定理知识求解) 求解&#…

wordpress 主题开发

https://www.cnblogs.com/welhzh/p/6937243.html wordpress 主题开发 https://yusi123.com/3205.html https://themeshaper.com/2012/10/22/the-themeshaper-wordpress-theme-tutorial-2nd-edition/ https://codex.wordpress.org/Theme_Frameworks https://lorelle.wordpre…

CentOS6.4下安装TeamViewer8

今天测试selenium调用firefoxdriver&#xff0c;该驱动无法在无界面环境中运行&#xff0c;需要远程连接到服务器进行操作&#xff0c;于是有了下面安装TeamViewer的过程。 先前尝试很多次也没有运行起来TeamViewer8&#xff0c;主要问题是安装后启动时候&#xff0c;没有出现授…