在任务并行库中:如何推迟Task.TaskFactory.FromAsync任务执行?

har*_*men 4 .net task-parallel-library

我有一个返回任务的方法,如:

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);
}
Run Code Online (Sandbox Code Playgroud)

我想保留对该任务的引用并稍后运行它.但是,似乎由FromAsync方法创建的任务立即执行.我怎样才能推迟执行?

小智 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);
}
Run Code Online (Sandbox Code Playgroud)

调用者将调用结果来启动操作(即调用FromAsync/BeginSend)并使用ContinueWith()来处理结果:

Func<Task<int>> sendAsync = socket.SendAsync(buffer, offset, count);
sendAsync().ContinueWith(
    antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));
Run Code Online (Sandbox Code Playgroud)

如果在您的界面中暴露Func <>是不合适的,您可以将它包装到一个单独的类中:

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));
}
Run Code Online (Sandbox Code Playgroud)

调用者看起来像:

DelayedTask<int> task = socket.SendAsync(buffer, offset, count);
task.Start().ContinueWith(
    antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));
Run Code Online (Sandbox Code Playgroud)