开源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 ...
随机推荐
- python 画图二(三维图,多轴图)
import sys reload(sys) sys.setdefaultencoding('utf-8') import matplotlib.pyplot as plt import numpy ...
- exp(cos(t)) - 2*cos(4.*t) + (sin(t./12)).^5;图形
clc; clear all; close all; t = linspace(0,24*pi,1000); r = exp(cos(t)) - 2*cos(4.*t) + (sin(t./12)). ...
- Docker教程:使用Docker容器运行Nginx并实现反向代理
一.前言 我们知道,为了安全考虑,我们一般会设置反向代理,用来屏蔽应用程序真实的IP和端口号.在Linux系统上最常用的反向代理就是Nginx.本篇文章中,我们会通过Docker容器分别运行一个Ngi ...
- CSS的各种重要属性
CSS属性图 01文字属性 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- Access denied for user ''@'localhost' to database 'mysql'问题
Access denied for user ''@'localhost' to database 'mysql'问题 MySQL : Access denied for user ''@'local ...
- Flowable学习入门
一.Flowable简介 1.Flowable是什么 Flowable是一个使用Java编写的轻量级业务流程引擎.Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标 ...
- SpringBoot 的多数据源配置
最近在项目开发中,需要为一个使用 MySQL 数据库的 SpringBoot 项目,新添加一个 PLSQL 数据库数据源,那么就需要进行 SpringBoot 的多数据源开发.代码很简单,下面是实现的 ...
- 史上最全java里面的锁
什么是锁 在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制.锁旨在强制实施互斥排他.并发控制策略. 锁通常需要硬件支持才能有效实施.这 ...
- Hadoop支持的压缩格式对比和应用场景以及Hadoop native库
对于文件的存储.传输.磁盘IO读取等操作在使用Hadoop生态圈的存储系统时是非常常见的,而文件的大小等直接影响了这些操作的速度以及对磁盘空间的消耗. 此时,一种常用的方式就是对文件进行压缩.但文件被 ...
- Linux服务器上搭建测试环境(war包+tomcat)
悟空CRM项目环境部署(Java war项目) 在/root目录下创建一个文件夹(名字自取). ls命令查看一下是否创建成功,看到了新建的文件夹说明创建成功. tomcat和war包的准备:可以使用X ...