У меня есть перечисление элементов (RunData.Demand), каждый из которых представляет собой некоторую работу, связанную с вызовом API через HTTP. Он отлично работает, если я всего лишь foreach через все это и вызываю API во время каждой итерации. Однако каждая итерация занимает секунду или два, поэтому я бы хотел запустить 2-3 потока и разделить работу между ними. Вот что я делаю:
ThreadPool.SetMaxThreads(2, 5); // Trying to limit the amount of threads
var tasks = RunData.Demand
.Select(service => Task.Run(async delegate
{
var availabilityResponse = await client.QueryAvailability(service);
// Do some other stuff, not really important
}));
await Task.WhenAll(tasks);
Вызов client.QueryAvailability в основном вызывает API с помощью класса HttpClient:
public async Task<QueryAvailabilityResponse> QueryAvailability(QueryAvailabilityMultidayRequest request)
{
var response = await client.PostAsJsonAsync("api/queryavailabilitymultiday", request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<QueryAvailabilityResponse>();
}
throw new HttpException((int) response.StatusCode, response.ReasonPhrase);
}
Это отлично работает некоторое время, но в конечном итоге все начинает отсчитываться. Если я установил HttpClient Timeout на час, тогда я начну получать странные внутренние ошибки сервера.
То, что я начал делать, это установить секундомер в методе QueryAvailability, чтобы узнать, что происходит.
Что происходит, все 1200 элементов в RunData.Demand создаются сразу и все 1200 await client.PostAsJsonAsync методов вызывают. Похоже, что он использует 2 потока для медленной проверки задач, поэтому к концу у меня есть задачи, ожидающие 9 или 10 минут.
Здесь поведение, которое я бы хотел:
Я хотел бы создать 1200 задач, а затем запускать их по 3-4 в то время, когда потоки становятся доступными. Я не хочу сразу поставить в очередь 1200 HTTP-вызовов.
Есть ли хороший способ сделать это?