Ваш пример кода написан не с учетом асинхронности.Вам не нужно Parallel.ForEach
вообще.HttpClient.GetAsync
уже асинхронен, и нет смысла его оборачивать в задачи, связанные с процессором .
private readonly _httpClient = new HttpClient();
var tasks = new List<Task>();
foreach(var url in urls)
{
var task = DoWork(url);
tasks.Add(task);
}
await Task.WhenAll(tasks);
foreach(var task in tasks)
{
if (task.Exception != null)
Console.WriteLine(task.Exception.Message);
}
public async Task DoWork(string url)
{
var json = await _httpClient.GetAsync(url);
// do something with json
}
Хотя Parallel.ForEach()
является более эффективной версией цикла и использует Task.Run()
этодействительно должен использоваться только для Связанного с процессором работы (Task.Run Etiquette and Proper Usage) .Вызов URL-адреса не связан с работой ЦП, это работа ввода-вывода (или более технически называемая Работа порта завершения ввода-вывода ).
ВЫ ИСПОЛЬЗУЕТЕ HTTPCLIIДЕСТАБИЛИЗИРУЕТ ВАШЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
Спасибо за ссылку HttpClient.Вот это да.Исправление кажется таким анти-паттерном.
Хотя это может показаться анти-паттерном, это потому, что предоставленное решение на самом деле является анти-паттерном.HttpClient
использует внешние ресурсы для выполнения своей работы, поэтому он должен располагаться (он реализует IDisposable
), но в то же время он должен использоваться как одиночный.Это создает проблему, потому что не существует чистого способа избавиться от синглтона, используемого в качестве статического свойства / поля в классе.Однако, поскольку он был написан mirosoft, мы не должны беспокоиться о том, что нам всегда нужно распоряжаться объектами, которые мы создаем, если в документации указано иное.
Поскольку вы указываете, чтони Parallel.ForEach, ни Task.Run не подходят для работы HttpClient, потому что он связан с вводом / выводом, что бы вы порекомендовали?
Async / Await
Я добавил миллионную часть к вопросу
Так что вам нужно ограничить количество параллельных задачитак:
var maximumNumberofParallelOperations = 1;
foreach(var url in urls)
{
var task = DoWork(url);
tasks.Add(task);
while (allTasks.Count(t => !t.IsCompleted) >= maximumNumberofParallelOperations )
{
await Task.WhenAny(allTasks);
}
}