开源AwaitableCompletionSource,用于取代TaskCompletionSource
1 TaskCompletionSource介绍
TaskCompletionSource提供创建未绑定到委托的任务,任务的状态由TaskCompletionSource上的方法显式控制,以支持未来的操作传播到它创建的任务。
使用场景
EAP(基于事件的异步模式)转TAP(基于任务的异步模式)
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;
}
结合CancellationTokenSource实现超时任务
public static async Task<string> DownloadStringAsync(Uri url, TimeSpan timeout)
{
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);
};
using var cts = new CancellationTokenSource();
cts.Token.Register(() => tcs.TrySetException(new TimeoutException()), useSynchronizationContext: false);
cts.CancelAfter(timeout);
wc.DownloadStringAsync(url);
return await tcs.Task;
}
不足之处
一个实例只支持创建一次任务
一个TaskCompletionSource<>实例,给它的任务设置结果或异常之后,这个实例就没有什么用了,既无法重置,也无法再创建新的任务实例。在高密集创建TaskCompletionSource<>要求的场景里,这可能给GC带来一点压力。
没有原生支持延时设置异常或结果功能
在网络请求里或更多场景里,可能会收不到或在特定的时间内收不到响应事件,这时TaskCompletionSource<>不得不和CancellationTokenSource结合使用,加上计时器完成超时功能,又多得创建一个对象实例。
2 AwaitableCompletionSource介绍
AwaitableCompletionSource的灵感来源于asp.netcore的kestrel的SocketAwaitableEventArgs,它把SocketAsyncEventArgs改装成支持单例可重复await的功能。AwaitableCompletionSource也支持单例可重复await,同时使用过后不再使用的实例还支持dispose回收到池中。
- 支持Singleton,单个实例持续使用;
- 支持Dispose后回收复用,创建实例0分配;
- 支持超时自动设置结果或异常,性能远好于TaskCompletionSource包装增加超时功能;
如何使用
使用方式与TaskCompletionSource大体一致。但是要使用静态类Create来创建实例,使用完成后Dispose实例。
var source = AwaitableCompletionSource.Create<string>();
ThreadPool.QueueUserWorkItem(s => ((IAwaitableCompletionSource)s).TrySetResult("1"), source);
Console.WriteLine(await source.Task);
// 支持多次设置获取结果
source.TrySetResultAfter("2", TimeSpan.FromSeconds(1d));
Console.WriteLine(await source.Task);
// 支持多次设置获取结果
source.TrySetResultAfter("3", TimeSpan.FromSeconds(2d));
Console.WriteLine(await source.Task);
// 实例使用完成之后,可以进行回收复用
source.Dispose();
3 性能比较
瞬态实例和调用TrySetResult
在频繁创建与回收AwaitableCompletionSource的场景,对于SetResult的使用,AwaitableCompletionSource的cpu时间明显高于TaskCompletionSource,但内存分配为0。
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|
| TaskCompletionSource_SetResult | 39.92 ns | 0.201 ns | 0.179 ns | 0.0229 | - | - | 96 B |
| AwaitableCompletionSource_SetResult | 86.19 ns | 0.315 ns | 0.295 ns | - | - | - | - |
单例和调用TrySetResult
单例AwaitableCompletionSource的场景,对于SetResult的使用,AwaitableCompletionSource与TaskCompletionSource的cpu时间相当,内存分配为0。
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|
| TaskCompletionSource_SetResult | 41.46 ns | 0.744 ns | 1.180 ns | 0.0229 | - | - | 96 B |
| AwaitableCompletionSource_SetResult | 49.30 ns | 0.528 ns | 0.494 ns | - | - | - | - |
瞬态实例和超时等待
注: TaskCompletionSource<>结合CancellationTokenSource<>实现超时。
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|
| TaskCompletionSource_WithTimeout | 237.0 ns | 4.76 ns | 5.85 ns | 0.1357 | - | - | 568 B |
| AwaitableCompletionSource_WithTimeout | 176.6 ns | 0.83 ns | 0.74 ns | - | - | - | - |
单例超时等待
注:AwaitableCompletionSource单例,TaskCompletionSource瞬态。
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|
| TaskCompletionSource_WithTimeout | 233.1 ns | 4.59 ns | 6.58 ns | 0.1357 | - | - | 568 B |
| AwaitableCompletionSource_WithTimeout | 131.5 ns | 1.41 ns | 1.32 ns | - | - | - | - |
4 总结
AwaitableCompletionSource在多个场景下可替代TaskCompletionSource,项目我已开源在https://github.com/xljiulang/AwaitableCompletionSource
开源AwaitableCompletionSource,用于取代TaskCompletionSource的更多相关文章
- 我发起了一个 .Net Core 平台上的 分布式缓存 开源项目 ShareMemory 用于 取代 Redis
Redis 的 安装 是 复杂 的, 使用 是 复杂 的, Redis 的 功能 是 重型 的, Redis 本身的 技术实现 是 复杂 的 . Redis 是用 C 写的, C 语言 编写的代码需要 ...
- PJNATH介绍 -- 开源的用于NAT穿透的ICE, STUN和TURN
原文地址:http://blog.pjsip.org/2007/04/06/introducing-pjnath-open-source-ice-stun-and-turn/ ICE是什么? 对于那些 ...
- 开源 XFControls , 用于 Xamarin.Forms 的自定义控件集
从此以后不会在博客园上发表任何言论,观注我的同志们,洗洗睡吧. ---------------------- 博文移至: http://www.jianshu.com/p/3ed1a3f10955
- IOS常用第三方开源类库&组件
1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功能强大, 现在许多人 ...
- 网易新闻iOS版使用的18个开源组件
转载来自:http://www.jianshu.com/p/8952944f7566 原文最后编辑时间:2015.05.19 网易新闻iOS版在开发过程中曾经使用过的第三方开源类库.组件 1.AFN ...
- iOS 常用开源代码整理
本文章不定期整理. 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功 ...
- 直接拿来用!Facebook移动开源项目大合集
直接拿来用!Facebook移动开源项目大合集 时间:2014-04-22 15:37 作者:唐小引 随着iOS依赖管理工具CocoaPods和大量第三方开源库成熟起来,业界积累了大量的优秀开源项目. ...
- apache基金会开源项目简介
apache基金会开源项目简介 项目名称 描述 HTTP Server 互联网上首屈一指的HTTP服务器 Abdera Apache Abdera项目的目标是建立一个功能完备,高效能的IETF ...
- ios很好的开源库
Tim9Liu9/TimLiu-iOS 自己总结的iOS.mac开源项目及库,持续更新.. 目录 UI 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关与Tabbar 隐藏与显示 HUD ...
随机推荐
- QEMU/KVM网络模式(二)——NAT
在QEMU/KVM中,默认使用IP伪装的方式去实现NAT,而不是用SNAT或DNAT的方式. 1.安装软件包 # yum -y install bridge-utils iptables dnsmas ...
- 对着爬虫网页HTML学习Python正则表达式re
1.正则表达式初探 用比较经典的例子,查找一段文本中的手机号码.比如对于文本"我现在用的电话是188-8888-8888,之前那个186-6666-6666已经不用了",我们想获取 ...
- Python进阶——什么是上下文管理器?
在 Python 开发中,我们经常会使用到 with 语法块,例如在读写文件时,保证文件描述符的正确关闭,避免资源泄露问题. 你有没有思考过, with 背后是如何实现的?我们常常听到的上下文管理器究 ...
- 在matlab 画箭头
[转载]在matlab 画箭头 原文地址:在matlab 画箭头作者:纯情小郎君 完整见链接http://www.mathworks.com/matlabcentral/fx_files/14056/ ...
- VS2019开启调试,测试图片上传的时候,一点到图片上传,直接导致VS调试崩掉,返回 程序“[14764] iisexpress.exe”已退出,返回值为 -1 (0xffffffff)。 是什么原因导致的?
试着使用管理员身份运行vs 今天调试的时候遇到个奇葩问题 一点上传控件选择文件后 就终止调试 发现根源不在上传控件 而是本地的中文输入法!关掉vs自动终止调试设置就好了 工具->选项-> ...
- ucore操作系统学习(七) ucore lab7同步互斥
1. ucore lab7介绍 ucore在前面的实验中实现了进程/线程机制,并在lab6中实现了抢占式的线程调度机制.基于中断的抢占式线程调度机制使得线程在执行的过程中随时可能被操作系统打断,被阻塞 ...
- 使用ajax请求上传多个或者多个附件
jsp页面 <%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML> ...
- CentOS Linux SVN服务器 配置用户目录访问 权限 Authorization failed
SVN 修改 aurhz 文件设置用户目录访问权限格式: [/code] user=rw user 用户对code目录拥有读和写的权限. 但是访问 svn://192.168.1.59 的时候却提示A ...
- rocketmq 架构设计
1 消息存储 消息存储是RocketMQ中最为复杂和最为重要的一部分,本节将分别从RocketMQ的消息存储整体架构.PageCache与Mmap内存映射以及RocketMQ中两种不同的刷盘方式三方面 ...
- Java异常体系概述
Java的异常体系结构 Java异常体系的根类是 Throwable, 所以当写在java代码中写throw抛出异常时,后面跟的对象必然是Throwable或其子类的对象. 其中Exception异常 ...