它所知道的就是,在某个时刻,它的SetResult
或SetException
方法被调用,以完成通过其Task
属性公开的Task<T>
。
换句话说,它充当Task<TResult>
及其完成的生产者。
我在示例中看到了:
如果我需要一种异步执行Func<T>
的方法,并且需要一个Task<T>
来表示该操作,则使用
。
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
的假设情况相关
发布于 2013-03-10 06:31:23
我主要在只有基于事件的API可用时使用它(for example Windows Phone 8 sockets):
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
关键字一起使用时特别有用。
发布于 2014-02-02 02:29:00
根据我的经验,TaskCompletionSource
非常适合将旧的异步模式包装成现代的async/await
模式。
我能想到的最有益的例子是在使用Socket
时。它具有旧的APM和EAP模式,但没有TcpListener
和TcpClient
所具有的awaitable Task
方法。
我个人对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();
发布于 2013-03-10 15:16:20
对我来说,使用TaskCompletionSource
的一个经典场景是,我的方法可能不一定要执行耗时的操作。它允许我们选择我们想要使用新线程的特定情况。
一个很好的例子是当你使用缓存的时候。您可以使用GetResourceAsync
方法,该方法在缓存中查找请求的资源,如果找到资源,则立即返回(不使用新线程,使用TaskCompletionSource
)。只有在没有找到资源的情况下,我们才会使用一个新线程,并使用Task.Run()
检索它。
代码示例可以在这里看到:How to conditionally run a code asynchonously using tasks
https://stackoverflow.com/questions/15316613
复制相似问题