it-swarm.com.ru

Что именно происходит, вызывая асинхронный метод без ключевого слова await?

У меня есть веб-сервер, и есть периодические задания слияния и отправки записей (много журналов запросов). 

Task.Run(() =>
{
    while (true)
    {
        try
        {
            MergeAndPutRecords();
        }
        catch (Exception ex)
        {
            Logger.Error(ex);
        }
    }
});

В функции MergeAndPutRecords есть записи слияния кода, и асинхронная функция возвращает записи отправки задач. (На самом деле это Amazon Kinesis Firehose's PutRecordBatchAsync .)

Что произойдет, если я вызову эту функцию без ключевого слова await? Работает ли функция в отдельном потоке? Здесь говорится, что это не . Тогда что же значит возвращать Task Task? Здесь говорит асинхронный метод без ключевого слова await означает 

  1. Запускает асинхронный метод в текущем потоке. Игнорирует все результаты (включая исключения).

Тогда моя периодическая работа и PutRecordBatchAsync обрабатываются одновременно? Я знаю, что асинхронный и параллельный разные. Но здесь нет ключевого слова await, и они находятся в одной теме. Какой из них будет казнен первым? Я путаю ...

Там будут огромные записи, которые должны быть объединены и отправлены в режиме реального времени. Поэтому я думаю, что это должно быть выполнено одновременно ..

7
YB Yu

Тогда моя периодическая работа и PutRecordBatchAsync обрабатываются одновременно?

Используя Task API, вы можете гарантировать, что они выполняются одновременно (с помощью пула потоков), но вы должны понимать разницу между параллельными операциями в памяти Vs IO параллелизм на основе.

В то время как в параллелизме памяти полезно использовать Tasks, вызову IO после выполнения не нужен поток вообще, так как он полагается на аппаратный параллелизм, если он когда-либо использует поток, все, что он будет делать, - это ждать IO призыв к возврату, тратя таким образом драгоценные системные ресурсы и снижая масштабируемость системы

В вашем случае это IO параллелизм на основе, когда вы называете удаленный/сетевой API, как здесь помогает async-await?

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

Что если вы не используете await с async?

Вызов, предназначенный для Asynchronous, становится Synchronous и немедленно повлияет на масштабируемость системы, поскольку потоки теперь заблокированы, что еще хуже для длительных операций IO. Вы видели, как фреймворки JavaScript всегда вызывают AJAX (Async) для API сервера, таким образом, гораздо больше работы возможно без блокирования потоков браузера.

В целом, для обработки в памяти вы должны создать определенное количество задач и обработать их, используя Task.WaitAll или Parallel.ForEach для коллекции, для асинхронной обработки в идеале не рекомендуется иметь где-либо Task.Run, предпочтительнее Async от точки входа, например это возможно в случае MVC, контроллеры могут быть асинхронными. Несколько вызовов группируются вместе с помощью Task.WhenAll типовой задачи, а затем ожидаются. даже если вы используете Task.Run как в своем коде, тогда используйте async lambda для выполнения асинхронного вызова

Резюме :

Обязательно использовать await для асинхронных вызовов, иначе ключевое слово async в этом контексте бесполезно, и yes await будет ожидать возврата вызова IO, прежде чем будет выполнено продолжение, хотя ни один поток не заблокирован в процессе

7
Mrinal Kamboj

Если метод возвращает Task, всегда рекомендуется наблюдать за результатом этого Task в какой-то момент. Это может быть объявленное возвращаемое значение или исключение. Если вы хотите наблюдать за этой задачей до продолжения вашего метода, рекомендуется await.

В этом случае вы, вероятно, должны наблюдать за результатом Task, возвращаемым PutRecordBatchAsync. Вы захотите узнать, произошел ли сбой по какой-либо причине, поскольку это, вероятно, означает, что ваши записи не были сохранены!

В приведенном вами примере кода вы обнаружите, что делаете последующие вызовы MergeAndPutRecords до завершения предыдущего вызова. Вы уверены, что это предназначено?

0
Gusdor