我有一个返回任务的方法,如:
public static Task<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
if (socket == null) throw new ArgumentNullException("socket");
if (buffer == null) throw new ArgumentNullException("buffer");
return Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndSend);
}
我想保留对该任务的引用并稍后运行它。但是,似乎由FromAsync方法创建的任务立即执行。我怎样才能推迟它的执行?
答案 0 :(得分:5)
如果你的接口要求你返回一个任务,你可能最终不必要地调度线程池上的工作只是为了进行BeginSend()调用(这是在上一个回答中发生的事情,其中FromAsync()调用被包装通过另一个任务)。
相反,如果您能够更改界面,则可以使用标准的延迟执行技术,例如:
public static Func<Task<int>> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
if (socket == null) throw new ArgumentNullException("socket");
if (buffer == null) throw new ArgumentNullException("buffer");
return () =>
Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndSend);
}
调用者将调用结果来启动操作(即调用FromAsync / BeginSend)并使用ContinueWith()来处理结果:
Func<Task<int>> sendAsync = socket.SendAsync(buffer, offset, count);
sendAsync().ContinueWith(
antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));
如果暴露Func&lt;&gt;在你的界面不合适,你可以把它包装成一个单独的类:
public class DelayedTask<TResult>
{
private readonly Func<Task<TResult>> func;
public DelayedTask(Func<Task<TResult>> func)
{
this.func = func;
}
public Task<TResult> Start()
{
return this.func();
}
}
public static DelayedTask<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
if (socket == null) throw new ArgumentNullException("socket");
if (buffer == null) throw new ArgumentNullException("buffer");
return new DelayedTask<int>(() =>
Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndSend));
}
调用者看起来像:
DelayedTask<int> task = socket.SendAsync(buffer, offset, count);
task.Start().ContinueWith(
antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));
答案 1 :(得分:1)
对于初学者来说,如果你看一下语法,你会发现你实际上是自己调用BeginSend
方法,并让它为FromAsync的第一个参数返回IAsyncResult
。这只是FromAsync的重载之一。如果您看到其他重载,那么您正在寻找的是那些取代Func<...>
的重载。不幸的是,这些重载也将立即代表您调用该方法,因为在幕后,真正发生的事情是FromAsync只是使用TaskCompletionSource<TResult>
包装APM调用模式。
我能够实际看到你能够推迟执行的唯一方法是将FromAsync
实际包装在你自己Start
的父任务中。例如:
public static Task<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
if (socket == null) throw new ArgumentNullException("socket");
if (buffer == null) throw new ArgumentNullException("buffer");
return new Task<int>(() =>
{
return Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndSend).Result;
}
}
现在调用者可以像这样完成任务:
Task<int> task = SendAsync(...);
直到他们致电task.Start()
,工作才会开始。
答案 2 :(得分:0)
用另一个任务包装任务可以推迟执行。
// Wrap the task
var myTask = new Task<Task<int>>(() => SendAsync(...));
// Defered start
Thread.Sleep(1000);
myTask.Start();
// Thread is not blocked
Console.WriteLine("Started");
// Wait for the result
Console.WriteLine(myTask.Unwrap().Result);