什么时候应该使用TaskCompletionSource <T>?

AFAIK,它所知道的只是在某个时候,它的SetResult或SetException方法被调用以Task<T>通过其Task属性完成公开。


换句话说,它充当a Task<TResult>及其完成的生产者。


我在这里看到了示例:


如果我需要一种异步执行Func并有一个Task来表示该操作的方法。


public static Task<T> RunAsync<T>(Func<T> function) 

    if (function == null) throw new ArgumentNullException(“function”); 

    var tcs = new TaskCompletionSource<T>(); 

    ThreadPool.QueueUserWorkItem(_ => 

    { 

        try 

        {  

            T result = function(); 

            tcs.SetResult(result);  

        } 

        catch(Exception exc) { tcs.SetException(exc); } 

    }); 

    return tcs.Task; 

}

*如果我没有,可以使用Task.Factory.StartNew-但我确实有Task.Factory.StartNew。


题:


可有人请举例相关的情景解释直接到TaskCompletionSource 而不是一个假想中,我没有的情况 Task.Factory.StartNew?


皈依舞
浏览 1279回答 3
3回答

杨魅力

以我的经验,TaskCompletionSource非常适合将旧的异步模式包装到现代async/await模式。我能想到的最有益的例子是使用Socket。它具有旧的APM和EAP模式,但没有和具有的awaitable Task方法。TcpListenerTcpClient我个人在NetworkStream班上有几个问题,更喜欢原始课程Socket。由于我也喜欢该async/await模式,因此我SocketExtender创建了一个扩展类,该类为创建了几个扩展方法Socket。所有这些方法都利用TaskCompletionSource<T>来包装异步调用,如下所示:&nbsp; &nbsp; public static Task<Socket> AcceptAsync(this Socket socket)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (socket == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentNullException("socket");&nbsp; &nbsp; &nbsp; &nbsp; var tcs = new TaskCompletionSource<Socket>();&nbsp; &nbsp; &nbsp; &nbsp; socket.BeginAccept(asyncResult =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var s = asyncResult.AsyncState as Socket;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var client = s.EndAccept(asyncResult);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tcs.SetResult(client);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch (Exception ex)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tcs.SetException(ex);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, socket);&nbsp; &nbsp; &nbsp; &nbsp; return tcs.Task;&nbsp; &nbsp; }我传递socket到BeginAccept方法,使我获得稍许的性能提升出来的没有扯起本地参数的编译器。那么这一切的美丽:&nbsp;var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);&nbsp;listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610));&nbsp;listener.Listen(10);&nbsp;var client = await listener.AcceptAsync();
打开App,查看更多内容
随时随地看视频慕课网APP