В задаче Параллельная библиотека: как отложить задание. Задача задачи. Fromasync Задача выполнения?

StackOverflow https://stackoverflow.com/questions/4031378

  •  26-09-2019
  •  | 
  •  

Вопрос

У меня есть метод, который возвращает задачу, как:

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);
}

Я хотел бы сохранить ссылку на задачу и запустить ее позже. Однако кажется, что задача, создаваемая методом PRYLASYNC, выполнена немедленно. Как я могу отложить его исполнение?

Это было полезно?

Решение

Для начала, если вы посмотрите на синтаксис, вы поймете, что вы на самом деле вызываете BeginSend метод самостоятельно и заставляя его вернуть IAsyncResult Для первого параметра peryasync. Это всего лишь одна из перегруженных перегрузок PerrySync. Если вы посмотрите, есть другие перегрузки, и те, которые вы ищете, это те, которые принимают Func<...> вместо. К сожалению, эти перегрузки также могут вызвать метод сразу от вашего имени из-за того, что в соответствии с охватами то, что действительно происходит, так это то, что fromasync просто обертывает шаблон вызова APM с использованием 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() Работа не начнется.

Другие советы

Если ваш интерфейс требует, чтобы вы вернули задачу, вы можете в конечном итоге без необходимости планирования работать на пуле резьбы, чтобы сделать вызов начнев () (это то, что происходит в предыдущем ответе, где вызов roysync () завернут другую задачу ).

Вместо этого, если вы можете изменить интерфейс, вы можете использовать стандартную технику исполнения задержки, такие как:

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);
}

Вызывающий абоненты вызовут результат, чтобы запустить операцию (т. Е. Вызов roysync / allendend) и использовать продолжение () для обработки результата:

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

Если выставляя функцию функции <> в вашем интерфейсе не подходит, вы можете обернуть его в отдельный класс:

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