我有一个方法,该方法返回像一个任务:

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方法创建的任务。我怎样才能延缓它的执行?

有帮助吗?

解决方案

对于初学者来说,如果你看一下语法,你就会意识到你其实自己在调用BeginSend方法,并使其返回IAsyncResult为FromAsync的第一个参数。这只是FromAsync不过的重载之一。如果你看到有其他重载和你正在寻找的那些是采取Func<...>代替的。不幸的是,这些重载还将调用就代表你的方法,因为这样的事实,在幕后,真正的情况是,FromAsync使用的 TaskCompletionSource<TResult>

我其实可以看到你能够推迟执行的唯一方法是实际包裹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()工作不会开始。

其他提示

如果您的接口要求您返回一个任务,你可能最终在线程池不必要的调度工作,只是为了让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键<>是不恰当的,你可以把它包装成一个单独的类:

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."));

与另一个任务中包装任务可以推迟执行。

  // 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);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top