开源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 ...
随机推荐
- JS C# 正则表达式去除html字符中所有的标签(img em标签除外)
js去除em标签 $(this).html().replace(/<(?!em|\/em).*?>/g, '') C#去除 System.Text.RegularExpressions.R ...
- Winform程序及dll打包成一个可执行的exe
使用场景 通常开发的Winform程序,引用了其他类库后,在输出目录下都会产生很多DLL文件,exe执行时必须依赖这些DLL.想要Winform程序只有一个可执行exe文件,又不想打包成安装包,就可以 ...
- 广告计价方式:CPM,CPC,CPA
转自知乎链接:https://www.zhihu.com/question/20416888/answer/15076251 1.CPM 收费最科学的办法是按照有多少人看到你的广告来收费.按访问人次收 ...
- H5-地理定位/本地存储/拖放
一.地理定位 Geolocation 兼容性:Internet Explorer 9+, Firefox, Chrome, Safari 和 Opera 支持Geolocation(地理定位). 一次 ...
- ProceedingJoinPoint 某些方法记录一下
转载与百度知道,记录一下.遇到在去看API 官方文档//拦截的实体类 Object target = point.getTarget(); //拦截的方法名称 String methodName = ...
- Thymeleaf Shiro标签
记录一下 guest标签 <shiro:guest> </shiro:guest> 用户没有身份验证时显示相应信息,即游客访问信息. user标签 <shiro:user ...
- ES6中class的使用+继承
一.Class 介绍+基本语法(1).介绍通过class关键字,可以定义类.基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的 ...
- 第三章 存储器的扩展(二)——> 重要
3.2 主存储器 四.只读存储器(ROM)---->了解(考试也可能会考) 掩膜ROM(MROM) 行列选择线交叉处有 MOS 管为"1" 行列选择线交叉处无 MOS 管为& ...
- 痞子衡嵌入式:MCUBootUtility v3.0发布,开始支持LPC, Kinetis啦
-- 痞子衡维护的NXP-MCUBootUtility工具距离上一个版本(v2.4.0)发布过去2个半月了,这一次痞子衡为大家带来了全新版本v3.0.0,从这个版本开始,NXP-MCUBootUtil ...
- Linux下最常用的10个文件压缩工具
作者简介 李先生(Lemon),高级运维工程师(自称),SRE专家(目标),梦想在35岁买一辆保时捷.喜欢钻研底层技术,认为底层基础才是王道.一切新技术都离不开操作系统(CPU.内存.磁盘).网络等. ...