Давайте сравним поведение вашей строки:
await Task.WhenAll(tasks.AsParallel().Select(async task => await task));
в отличие от:
await Task.WhenAll(tasks);
Что вы делегируете PLINQ в первом случае? Только операция await
, которая в принципе ничего не делает - она вызывает механизм async
/ await
для ожидания одного task
. Таким образом, вы настраиваете запрос PLINQ, который выполняет всю тяжелую работу по разбиению и объединению результатов операции, которая составляет «ничего не делать, пока этот task
не завершится». Я сомневаюсь, что это то, что вы хотите.
Если у вас есть другие методы ожидания в ваших методах, Task.WhenAll () не поможет, так как методы Asyn c не параллельны.
Я не смог найти это ни в одном из ответов на связанные вопросы, кроме одного комментария под самим вопросом. Я бы сказал, что это, вероятно, неправильное представление, вытекающее из того факта, что async
/ await
волшебным образом не превращает ваш код в параллельный код. Но, предполагая, что вы находитесь в среде без пользовательского SynchronizationContext
(т.е. не ASP или приложения WPF), продолжения функций async
будут запланированы в пуле потоков и, возможно, будут выполняться параллельно. Я поручу вам этот ответ , чтобы пролить свет на это. По сути это означает, что если ваш SendAsync
выглядит примерно так:
Task SendAsync(IMessage message)
{
// Synchronous initialization code.
await something;
// Continuation code.
}
Тогда:
- Первая часть до await выполняется синхронно. Если эта часть имеет большой вес, вы должны ввести параллелизм в
SendAll
, чтобы код инициализации выполнялся параллельно. await
работает как обычно, ожидая завершения работы без использования каких-либо потоков. - Код продолжения будет запланирован в пуле потоков, поэтому, если несколько
await
s fini sh одновременно работают, их продолжения могут выполняться параллельно , если В пуле потоков достаточно потоков.
Все вышеизложенное предполагает, что await something
фактически ожидает асинхронно. Если есть вероятность, что await something
завершится синхронно, то код продолжения также будет выполняться синхронно.
Теперь есть ловушка. В вопросе, который вы связали, одно из ответов гласит:
Task.WhenAll()
имеет тенденцию выходить из строя с большим количеством задач, выполняемых одновременно - без модерации / регулирования.
Теперь я не знаю, правда ли это, поскольку я не смог найти другого источника, который бы заявлял об этом. Я предполагаю, что это возможно, и в этом случае на самом деле может быть полезно вызвать PLINQ, чтобы иметь дело с разделением и регулированием для вас. Однако вы сказали, что обычно обрабатываете 1-5 функций, поэтому вам не стоит об этом беспокоиться.
Итак, подведем итог: параллелизм сложен, и правильный подход зависит от того, как именно выглядит ваш метод SendAsync
. Если он имеет тяжелый код инициализации и это то, что вы хотите распараллелить, вы должны выполнить все вызовы к SendAsync
параллельно. В противном случае async
/ await
все равно будет неявно использовать пул потоков, поэтому ваш вызов PLINQ является избыточным.