zoukankan      html  css  js  c++  java
  • 开源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

  • 相关阅读:
    步步为营 C# 技术漫谈 一、反射机制
    Windows API、CRT和STL
    MVC3 基本业务开发框架
    .NET实现之(WebBrowser数据采集—终结篇)
    步步为营 C# 技术漫谈 二、ASP.NET 页生命周期
    步步为营 .NET 代码重构学习笔记 十
    步步为营 .NET 代码重构学习笔记 十三
    MagicDict开发总结6 [划词 检索]
    步步为营 .NET 代码重构学习笔记系列总结
    项目多少是可以配置的?
  • 原文地址:https://www.cnblogs.com/kewei/p/14339919.html
Copyright © 2011-2022 走看看