AFAIK,它所知道的只是在某些时候,它的SetResult或SetException方法被调用来完成通过Task属性暴露的Task<T>。
换句话说,它充当Task<TResult>及其完成的生产者。
我在这里看到了一个例子:
如果我需要一种方法来异步执行Func<T>,并有一个任务<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 ?
根据我的经验,TaskCompletionSource非常适合将旧的异步模式包装到现代的异步/await模式中。
我能想到的最有用的例子是使用Socket。它具有旧的APM和EAP模式,但没有TcpListener和TcpClient所具有的可等待的任务方法。
我个人对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;
}
我将套接字传递给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();
TaskCompletionSource is used to create Task objects that don't execute code.
In real world scenarios, TaskCompletionSource is ideal for I/O bound operations. This way, you get all the benefits of tasks (e.g. return values, continuations, etc) without blocking a thread for the duration of the operation. If your "function" is an I/O bound operation, it isn't recommended to block a thread using a new Task. Instead, using TaskCompletionSource, you can create a slave task to just indicate when your I/O bound operation finishes or faults.