Части вашего кода, которые вы нам показали, не работают асинхронно.Вы звоните .Result
на GetResponseContentAsync()
, который заблокирует поток, пока он не завершит .Это означает, что к моменту завершения Parallel.ForEach
все запросы HTTP будут завершены.
Если вы используете await
где-то в этом блоке кода, который вы заменили на
// set values form the responseProduct to the product
тогда возможно, что результаты не будут сообщены до окончания Parallel.ForEach
.Это потому, что Parallel.ForEach
не поддерживает асинхронный код, поэтому он не будет ждать их завершения.
Предположим, что GetProductsInfo
на самом деле работает асинхронно
Тогда проблема в том, что Parellel.ForEach
не ждет завершения моих асинхронных операций.Есть несколько способов справиться с этим.
- Реализуйте свой собственный
ForEachAsync
.Это было запрошено и, вероятно, будет добавлено (по крайней мере, в .NET Core).Но на самом деле есть пример реализации в проблема, где это было запрошено :
/// <summary>
/// Executes a foreach asynchronously.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="dop">The degrees of parallelism.</param>
/// <param name="body">The body.</param>
/// <returns></returns>
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in System.Collections.Concurrent.Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate
{
using (partition)
{
while (partition.MoveNext())
await body(partition.Current);
}
}));
}
Это написано как метод расширения, поэтому вы должны использовать его следующим образом:
await products.ForEachAsync(10, GetProductsInfo);
Где 10
- номер запроса, который вы хотите выполнить за раз.
Вы можете использовать что-то вроде:
Task.WaitAll(items.Select(i => GetProductsInfo(i));
Это будет выполнять запросы асинхронно, но блокировать вызывающий поток, пока все они не завершатся.Кроме того, вы можете await
их, чтобы он не блокировал вызывающий поток:
await Task.WhenAll(items.Select(i => GetProductsInfo(i))
Однако оба этих метода будут запускать всех запросов одновременно.Если вы знаете, что у вас будет только небольшое число, тогда это нормально.Но если у вас может быть очень большое количество, вы можете залить веб-сервис.Использование Parallel.ForEach
, или реализация ForEachAsync
выше отправит их в блоках.
Если вы используете любой из этих методов для ожидания ответов, тогда вам действительно следует ждать GetResponseContentAsync
вместо использования .Result
:
var responseProduct = await GetResponseContentAsync(restClientProduct, restRequestProduct);
Использование async
/ await
особенно важно в ASP.NET, где существует максимальное количество потоков, которое он может использовать.