Я использую клиент API, который является полностью асинхронным, то есть каждая операция либо возвращает, Task
либо Task<T>
, например:
static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
await client.DeletePost(siteId, postId); // call API client
Console.WriteLine("Deleted post {0}.", siteId);
}
Используя асинхронные / ожидающие операторы C # 5, каков правильный / наиболее эффективный способ запуска нескольких задач и ожидания их выполнения:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
или:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
Поскольку клиент API использует HttpClient для внутреннего использования, я ожидаю, что он немедленно выдаст 5 HTTP-запросов, записывая их на консоль по завершении каждого из них.
c#
.net
task-parallel-library
async-await
c#-5.0
Бен Фостер
источник
источник
Ответы:
Хотя вы выполняете операции параллельно с приведенным выше кодом, этот код блокирует каждый поток, в котором выполняется каждая операция. Например, если сетевой вызов занимает 2 секунды, каждый поток зависает на 2 секунды без каких-либо действий, кроме ожидания.
С другой стороны, приведенный выше код
WaitAll
также блокирует потоки, и ваши потоки не смогут свободно обрабатывать любую другую работу до завершения операции.Рекомендуемый подход
Я бы предпочел,
WhenAll
который будет выполнять ваши операции асинхронно в параллель.Чтобы поддержать это, вот подробное сообщение в блоге, в котором рассматриваются все альтернативы и их преимущества / недостатки: как и где одновременный асинхронный ввод-вывод с ASP.NET Web API
источник
WaitAll
также блокирует потоки» - разве он не блокирует только один поток, который вызвалWaitAll
?Мне было любопытно увидеть результаты методов, представленных в вопросе, а также принятый ответ, поэтому я проверил его.
Вот код:
И полученный результат:
источник
Поскольку вызываемый API является асинхронным,
Parallel.ForEach
версия не имеет особого смысла. Вы не должны использовать.Wait
вWaitAll
версии, так как это потеряло бы параллелизм. Другая альтернатива, если вызывающий объект асинхронный, используетTask.WhenAll
после выполненияSelect
иToArray
для генерации массива задач. Второй альтернативой является использование Rx 2.0источник
Вы можете использовать
Task.WhenAll
функцию, которую вы можете передать n задач;Task.WhenAll
вернет задачу, которая выполняется до завершения, когда все задачи, которые вы передали дляTask.WhenAll
завершения. Вы должны ждать асинхронно,Task.WhenAll
чтобы не блокировать поток пользовательского интерфейса:источник
Parallel.ForEach
требует список определенных пользователем рабочих и не асинхронныйAction
для выполнения с каждым рабочим.Task.WaitAll
иTask.WhenAll
требуютList<Task>
, которые по определению являются асинхронными.Я нашел RiaanDP «S ответ очень полезно , чтобы понять разницу, но она нуждается в коррекции для
Parallel.ForEach
. Недостаточно репутации, чтобы ответить на его комментарий, следовательно, мой собственный ответ.Результирующий вывод ниже. Время исполнения сопоставимо. Я запустил этот тест, пока мой компьютер еженедельно проверял антивирус. Изменение порядка тестов изменило время их выполнения.
источник