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的更多相关文章

  1. 我发起了一个 .Net Core 平台上的 分布式缓存 开源项目 ShareMemory 用于 取代 Redis

    Redis 的 安装 是 复杂 的, 使用 是 复杂 的, Redis 的 功能 是 重型 的, Redis 本身的 技术实现 是 复杂 的 . Redis 是用 C 写的, C 语言 编写的代码需要 ...

  2. PJNATH介绍 -- 开源的用于NAT穿透的ICE, STUN和TURN

    原文地址:http://blog.pjsip.org/2007/04/06/introducing-pjnath-open-source-ice-stun-and-turn/ ICE是什么? 对于那些 ...

  3. 开源 XFControls , 用于 Xamarin.Forms 的自定义控件集

    从此以后不会在博客园上发表任何言论,观注我的同志们,洗洗睡吧. ---------------------- 博文移至: http://www.jianshu.com/p/3ed1a3f10955

  4. IOS常用第三方开源类库&组件

    1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功能强大, 现在许多人 ...

  5. 网易新闻iOS版使用的18个开源组件

    转载来自:http://www.jianshu.com/p/8952944f7566  原文最后编辑时间:2015.05.19 网易新闻iOS版在开发过程中曾经使用过的第三方开源类库.组件 1.AFN ...

  6. iOS 常用开源代码整理

    本文章不定期整理. 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功 ...

  7. 直接拿来用!Facebook移动开源项目大合集

    直接拿来用!Facebook移动开源项目大合集 时间:2014-04-22 15:37 作者:唐小引 随着iOS依赖管理工具CocoaPods和大量第三方开源库成熟起来,业界积累了大量的优秀开源项目. ...

  8. apache基金会开源项目简介

    apache基金会开源项目简介   项目名称 描述 HTTP Server 互联网上首屈一指的HTTP服务器 Abdera Apache  Abdera项目的目标是建立一个功能完备,高效能的IETF ...

  9. ios很好的开源库

    Tim9Liu9/TimLiu-iOS 自己总结的iOS.mac开源项目及库,持续更新.. 目录 UI 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关与Tabbar 隐藏与显示 HUD ...

随机推荐

  1. 【译】理解Rust中的Futures(二)

    原文标题:Understanding Futures in Rust -- Part 2 原文链接:https://www.viget.com/articles/understanding-futur ...

  2. Java与C#的代码区别

    Java和C#都是编程的语言,它们是两个不同方向的两种语言 相同点: 他们都是面向对象的语言,也就是说,它们都能实现面向对象的思想(封装,继承,多态) 区别: 1.c#中的命名空间是namespace ...

  3. 面试官让你讲讲Linux内核的竞争与并发,你该如何回答?

    @ 目录 内核中的并发和竞争简介 原子操作 原子操作简介 整型原子操作函数 位原子操作函数 原子操作例程 自旋锁 自旋锁简介 自旋锁操作函数 自旋锁例程 读写自旋锁 读写锁例程 顺序锁 顺序锁操作函数 ...

  4. 使用IDE练习插件【廖雪峰】

    使用廖雪峰大神的插件,安装过程中,一直出现问题,然后在他的Java教程下面看大家的评论也有点晕了(很多人说的是jar包,结果其实是下的依旧是zip包) 最终解决方法: 将zip包解压到同名文件夹中,再 ...

  5. Spring Boot面试杀手锏————自动配置原理

    转:https://blog.csdn.net/u014745069/article/details/83820511 引言不论在工作中,亦或是求职面试,Spring Boot已经成为我们必知必会的技 ...

  6. Android驱动学习-app调用内核驱动过程(驱动框架回顾)

    考研已经过去了,android驱动的学习也断了半年多了,现在重新捡起来学习,回顾一下Android驱动的大体框架. Android系统的核心是java,其有一个David虚拟机.Android-app ...

  7. 访问需要HTTP Basic Authentication认证的资源的c#的实现

    string username="username"; string password="password"; //注意这里的格式哦,为 "usern ...

  8. Java基础经典案例

    案例列表 01减肥计划switch版本 02减肥计划if版本 03逢七跳过 04不死神兔 05百钱白鸡 06数组元素求和 07判断两个数组是否相同 08查找元素在数组中的索引 09数组元素反转 10评 ...

  9. .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ 工作队列和交换机)--学习笔记

    2.6.4 RabbitMQ -- 工作队列和交换机 WorkQueue Publish/Subscribe Routing EmitLog WorkQueue WorkQueue:https://w ...

  10. Kali Debian 修改时区

    1.KaliDebian默认读取时区文件是/etc/localtime(重建软连接,达到修改时区目的) 2./etc/localtime是个软连接,连接到时区文件/usr/share/zoneinfo ...