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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (22)

什么时候应该使用TaskCompletionSource?

AFAIK,它所知道的就是在某一时刻,SetResultSetException方法来完成Task<T>通过其Task财产。

换句话说,它作为一个Task<TResult>以及它的完成。

例子:

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

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.

提问于
用户回答回答于

当只有基于事件的API可用时:

public Task<Args> SomeApiWrapper()
{
    TaskCompletionSource<Args> tcs = new TaskCompletionSource<Args>(); 

    var obj = new SomeApi();

    // will get raised, when the work is done
    obj.Done += (args) => 
    {
        // this will notify the caller 
        // of the SomeApiWrapper that 
        // the task just completed
        tcs.SetResult(args);
    }

    // start the work
    obj.Do();

    return tcs.Task;
}

因此,当与c#5一起使用时,它特别有用。async关键词。

用户回答回答于

在我的经历中,TaskCompletionSource很适合将旧的异步模式包装到现代。async/await模式。

我能想到的最有益的例子是在使用时Socket。它有旧的APM和EAP模式,但没有awaitable Task方法TcpListenerTcpClient有。

我个人对NetworkStream类和喜欢生的Socket。因为我也喜欢async/await模式,我做了一个扩展类SocketExtender创建几个扩展方法Socket.

所有这些方法都是利用TaskCompletionSource<T>要包装异步调用,如下所示:

    public static Task<Socket> AcceptAsync(this Socket socket)
    {
        if (socket == null)
            throw new ArgumentNullException("socket");

        var tcs = new TaskCompletionSource<Socket>();

        socket.BeginAccept(asyncResult =>
        {
            try
            {
                var s = asyncResult.AsyncState as Socket;
                var client = s.EndAccept(asyncResult);

                tcs.SetResult(client);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }

        }, socket);

        return tcs.Task;
    }

我通过了socket进入BeginAccept方法,这样编译器就可以稍微提高性能,而不必提升本地参数。

这一切的美妙之处在于:

 var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610));
 listener.Listen(10);

 var client = await listener.AcceptAsync();

扫码关注云+社区