richtig in Warteschlange Ich habe eine Aufzählung von Elementen (RunData.Demand
), die jeweils einige Arbeit darstellen Aufruf einer API über HTTP. Es funktioniert gut, wenn ich nur foreach
über alles und rufen Sie die API während jeder Iteration. Allerdings dauert jede Iteration ein oder zwei Sekunden, also würde ich gerne 2-3 Threads ausführen und die Arbeit zwischen ihnen aufteilen. Hier ist, was ich tue:Wie ordne ich Aufgaben in 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);
Der client.QueryAvailability
Aufruf ruft im Grunde eine API mit der HttpClient
Klasse:
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);
}
Dies funktioniert gut für eine Weile, aber schließlich die Dinge beginnen Timing aus. Wenn ich das HttpClient Timeout auf eine Stunde setze, bekomme ich seltsame interne Serverfehler.
Was ich begann zu tun war eine Stoppuhr innerhalb der QueryAvailability
Methode, um zu sehen, was los war.
Was passiert, ist alle 1200 Elemente in RunData.Demand werden auf einmal erstellt und alle 1200 await client.PostAsJsonAsync
Methoden aufgerufen werden. Es scheint, dass es dann die 2 Threads verwendet, um die Aufgaben langsam zu überprüfen, so dass ich zum Ende Aufgaben habe, die auf 9 oder 10 Minuten gewartet haben.
Hier ist das Verhalten Ich mag würde:
Ich mag würde die 1200 Aufgaben erstellen und sie dann 3-4 zu einem Zeitpunkt ausgeführt als Threads verfügbar sind. Ich mache nicht wollen 1.200 HTTP-Anrufe sofort anstehen.
Gibt es einen guten Weg, dies zu tun?
Sie scheinen keinen neuen "Client" für jeden Anruf zu erstellen. Sie wissen, dass 'System.Net.Http.HttpClient' für Instanzaufrufe nicht Thread-sicher ist? Für jeden Aufruf sollte eine neue Instanz erstellt (und danach angeordnet) werden. – Enigmativity
Die QueryAvailability-Methode befindet sich tatsächlich in einer Klasse, die den HttpClient erstellt, der ein privates Mitglied dieser Instanz ist. Ich wusste nicht, dass es nicht Thread-sicher ist, aber ich könnte es definitiv vor jedem Anruf erstellen. Ich schaue mir das mehr an, danke! –
Hmm, ich habe ein bisschen recherchiert und es scheint, dass ich threadsicher bin. Siehe [hier] (http://stackoverflow.com/questions/11178220/is-httpclient-safe-to-use-concurrently) und [hier] (http://www.tomdupont.net/2014/11/net- 45-httpclient-is-thread-safe.html) –