У меня есть несколько асинхронных служб REST, которые не зависят друг от друга. То есть, пока «ожидая» ответа от Service1, я могу позвонить в Service2, Service3 и так далее.
Например, смотрите ниже код:
var service1Response = await HttpService1Async();
var service2Response = await HttpService2Async();
// Use service1Response and service2Response
Теперь service2Response
не зависит, service1Response
и они могут быть получены независимо. Следовательно, мне не нужно ждать ответа первой службы для вызова второй службы.
Я не думаю, что я могу использовать Parallel.ForEach
здесь, поскольку это не связано с процессором операции.
Можно ли вызвать эти две операции параллельно, могу ли я вызвать use Task.WhenAll
? Одна проблема, которую я вижу, Task.WhenAll
это то, что она не возвращает результаты. Чтобы получить результат, я могу позвонить task.Result
после вызова Task.WhenAll
, так как все задачи уже выполнены, и все, что мне нужно, чтобы получить нам ответ?
Образец кода:
var task1 = HttpService1Async();
var task2 = HttpService2Async();
await Task.WhenAll(task1, task2)
var result1 = task1.Result;
var result2 = task2.Result;
// Use result1 and result2
Этот код лучше, чем первый, с точки зрения производительности? Любой другой подход, который я могу использовать?
источник
I do not think I can use Parallel.ForEach here since it is not CPU bound operation
- Я не вижу логики там. Параллелизм - это параллелизм.Parallel.ForEach
будут порождаться новые потоки, тогда какasync await
все будет выполняться в одном потоке.await
), прежде чем он будет готов.WhenAll
перед тем, как делаюResult
мысль, что он завершает все задачи перед вызовом .Result. Поскольку Task.Result блокирует вызывающий поток, я предполагаю, что если я вызову его после фактического завершения задач, он немедленно вернет результат. Я хочу подтвердить понимание.Ответы:
Но это действительно возвращает результаты. Все они будут в массиве общего типа, поэтому не всегда полезно использовать результаты, так как вам нужно найти в массиве элемент, соответствующий тому, для
Task
которого вы хотите получить результат, и потенциально привести его к фактический тип, так что это может быть не самый простой / наиболее читаемый подход в этом контексте, но когда вы просто хотите получить все результаты из каждой задачи, а общий тип - это тип, к которому вы хотите относиться к ним, тогда это здорово ,Да, вы могли бы сделать это. Вы также можете
await
их использовать (await
разворачивать исключение в любой ошибочной задаче, тогда какResult
генерировало бы исключение агрегирования, но в противном случае оно было бы таким же).Он выполняет две операции одновременно, а не одну, а затем другую. Будет ли это лучше или хуже, зависит от того, каковы эти основные операции. Если основными операциями являются «чтение файла с диска», то параллельное выполнение их, вероятно, будет медленнее, поскольку имеется только одна головка диска и она может быть только в одном месте в любой момент времени; прыжок между двумя файлами будет медленнее, чем чтение одного файла, затем другого. С другой стороны, если операции «выполняют какой-то сетевой запрос» (как в данном случае), то они, скорее всего, будут быстрее (по крайней мере, до определенного числа одновременных запросов), потому что вы можете ждать ответа с какого-либо другого сетевого компьютера так же быстро, когда происходит также другой ожидающий сетевой запрос. Если вы хотите знать, если это
Если для вас не важно, что вы знаете все исключения, сгенерированные среди всех операций, которые вы выполняете параллельно, а не только первую, вы можете просто
await
выполнять задачиWhenAll
вообще. Единственное, чтоWhenAll
дает вам - это иметьAggregateException
с каждым исключением из каждой ошибочной задачи, а не бросать, когда вы нажимаете первую неисправную задачу. Это так просто, как:источник
Вот метод расширения, который использует SemaphoreSlim и позволяет установить максимальную степень параллелизма
Пример использования:
источник
Вы можете использовать
или
источник