Mam wyliczenie elementów (RunData.Demand
), z których każda przedstawia niektóre prace związane z wywoływaniem API przez HTTP. Działa to świetnie, jeśli tylko przez cały czas będę je wywoływać i wywoływać API podczas każdej iteracji. Jednak każda iteracja trwa sekundę lub dwie, więc chciałbym uruchomić 2-3 wątki i podzielić pracę między nimi. Oto, co robię:Jak prawidłowo ustawiać kolejki zadań do uruchomienia w języku C#
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
wezwanie zasadzie wywołuje API przy użyciu klasy 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);
}
Działa to doskonale na chwilę, ale w końcu wszystko zaczyna odmierzanie. Jeśli ustawię limit czasu HttpClient na godzinę, wtedy zaczną się dziwne błędy wewnętrznego serwera.
Zacząłem od ustawienia stopera w metodzie QueryAvailability
, aby sprawdzić, co się dzieje.
Co się dzieje, to 1200 pozycji w RunData.Demand są tworzone jednocześnie i wszystkie metody 1200 await client.PostAsJsonAsync
są wywoływane. Wygląda na to, że używa 2 wątków do powolnego sprawdzania zadań, więc pod koniec mam zadania, które czekają na 9 lub 10 minut.
Oto zachowanie Chciałbym:
Chciałbym stworzyć 1200 zadań, a następnie uruchomić je 3-4 naraz stają się dostępne wątki. Robię , a nie chcę od razu kolejkować 1 200 połączeń HTTP.
Czy jest dobry sposób na robienie tego?
Nie wydaje się, aby utworzyć nowego 'klienta' dla każdego połączenia. Wiesz, że 'System.Net.Http.HttpClient' nie jest wątkiem bezpiecznym dla wywołań instancji? Dla każdego wywołania należy utworzyć nową instancję dla (i usuwać po). – Enigmativity
Metoda 'QueryAvailability' jest faktycznie w klasie, która tworzy' HttpClient', który jest prywatnym członkiem tej instancji. Nie wiedziałem, że to nie jest wątek bezpieczne, mogę definitywnie utworzyć go przed każdym wywołaniem. Przyjrzę się temu więcej, dzięki! –
Hmm, zrobiłem trochę badań i wygląda na to, że to, co robię, jest bezpieczne dla wątków. Zobacz [tutaj] (http://stackoverflow.com/questions/11178220/is-httpclient-safe-to-use-concrentrently) i [tutaj] (http://www.tomdupont.net/2014/11/net- 45-httpclient-is-thread-safe.html) –