как использовать async и ждать, чтобы создать отдельную задачу или каждый запрос - PullRequest
0 голосов
/ 14 мая 2019

Я новичок в ядре asp.net и в асинхронном программировании. ниже мой код

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    var work = await TaskQueue.DequeueAsync(stoppingToken);
    while (!stoppingToken.IsCancellationRequested)
    {
        redirect(work);
    }
}

public async Task redirect(Func<CancellationToken, Task> work)
{
    await work();
}

Так что здесь, когда я запускаю программу и отлаживаю ее, курсор сначала идет в метод ExecuteAsync, а из цикла while он переходит в метод перенаправления. Метод перенаправления асинхронный, но он будет ждать метода работы. так что я думаю, что он не работает асинхронно.

Я ожидаю, что когда курсор перейдет в метод работы, он запустит новую задачу (Thread).

Ответы [ 2 ]

2 голосов
/ 14 мая 2019

когда я запускаю программу и отлаживаю ее

Наблюдаемое вами поведение - Visual Studio , пытающийся быть полезным. Он имеет специальный код для обработки асинхронных методов, поэтому, когда вы говорите «перейти к следующей строке», он не переходит внезапно к какому-либо совершенно не связанному методу; в этом методе он перейдет к следующей строке .

Я ожидаю, что когда курсор перейдет в метод работы, он запустит новую задачу (Thread).

Задачи не являются потоками. В частности, задачи, созданные методами async, не выполняются в потоках; это просто объекты состояния, которые могут уведомить другой код о завершении метода async.

Я рекомендую прочитать мое async вступление и дополнить его async рекомендациями .

1 голос
/ 14 мая 2019

Есть несколько недоразумений в том, как вы пытаетесь использовать Async-Await, в сети достаточно контента, ниже приведены конкретные детали:

Так что здесь, когда я запускаю программу и отлаживаю ее, курсор сначала идет в метод ExecuteAsync, а из цикла while он идет в метод перенаправления. Метод перенаправления асинхронный, но он будет ждать метода работы. так что я думаю, что он не работает асинхронно

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

Теперь, какая обработка work делает это IO или Compute

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

Относительно вашего кода

  • В текущей форме это код блокировки, так как в цикле while вы вызываете redirect(work), который, в свою очередь, выполняет await work, освобождает вызывающую программу, но ожидает его завершения, прежде чем может быть выполнена следующая асинхронная операция
  • Идеальный способ - собрать все задачи в коллекции, например, List<Task>, и когда вы ожидаете Task.WhenAll, тогда все объединенные задачи объединяются, в то время как вы асинхронно ждете у единственного представителя Task, чтобы все они выполнились. , это все равно не blcoking / call, как в текущем коде, а блокировка для полного агрегированного списка, это определяется @TheGeneral в комментариях, таким образом, помогает в лучшей обработке, так как все задачи идут вместе
  • Также await work() неверно, ошибка компиляции, для этого требуется токен отмены как параметр I / p
  • В текущем коде в идеале также следует ожидать redirect(work), асинхронное ожидание должно происходить по всей цепочке вызовов

Модифицированная версия вашего кода

При условии, что вам нужно Task.WhenAll, и вы выполняете асинхронную работу на основе ввода-вывода, ваш код будет следующим:

protected override async Task ExecuteAsync(CancellationToken stoppingQueueToken,CancellationToken stopWorkToken)
{
      var work = await TaskQueue.DequeueAsync(stoppingQueueToken);
      List<Task> taskList = new List<Task>();
      while (!stoppingQueueToken.IsCancellationRequested)
      {  
         taskList.Add(redirect(work, stopWorkToken));
      }

      await Task.WhenAll(taskList);
}

public async Task redirect(Func<CancellationToken, Task> work, CancellationToken stopWorkToken)
{
    await work(stopWorkToken);
}

Я взял на себя смелость представить дополнительный маркер отмены для отмены работы, так как обработка работы начинается только один раз, когда завершается цикл, до этого он просто объединяет задачи, затем все они обрабатываются в фоновом режиме, принимая IO на максимум выгода. Здесь также отладчик будет блокировать, но для всех задач вместе один вызов

Если вы сохраняете текущий код, вам просто нужно внести следующие изменения:

protected override async Task ExecuteAsync(CancellationToken stoppingQueueToken)
{
    var work = await TaskQueue.DequeueAsync(stoppingQueueToken);
    List<Task> taskList = new List<Task>();
    while (!stoppingQueueToken.IsCancellationRequested)
    {
        await redirect(work, stoppingQueueToken);
    }
}

public async Task redirect(Func<CancellationToken, Task> work, CancellationToken stoppingQueueToken)
{
    await work(stoppingQueueToken);
}
  • Этот код выполняется один за другим, все еще асинхронно и освобождает вызывающий контекст, но не все вместе. Отладчик заблокирует, как вы уже видели.

Немного подробнее

  • Task и Thread не являются одинаковыми и взаимозаменяемыми, несколько задач могут выполняться в одном потоке
  • Токен отмены является кооперативным, он не отменяет уже запущенную задачу, либо должен быть отменен до начала задачи, либо должен быть явно проверен и брошен для остановки выполнения задачи, ThrowIfCancellationRequested
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...