Ich verwende einen API-Client, der vollständig asynchron ist, dh jede Operation gibt entweder zurück Task
oder Task<T>
z.
static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
await client.DeletePost(siteId, postId); // call API client
Console.WriteLine("Deleted post {0}.", siteId);
}
Was ist mit den asynchronen / wartenden C # 5-Operatoren die richtige / effizienteste Methode, um mehrere Aufgaben zu starten und darauf zu warten, dass sie alle abgeschlossen sind:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
oder:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
Da der API-Client HttpClient intern verwendet, würde ich erwarten, dass dies sofort 5 HTTP-Anforderungen ausgibt, die nach Abschluss jeweils in die Konsole geschrieben werden.
c#
.net
task-parallel-library
async-await
c#-5.0
Ben Foster
quelle
quelle
Antworten:
Obwohl Sie die Operationen parallel zum obigen Code ausführen, blockiert dieser Code jeden Thread, auf dem jede Operation ausgeführt wird. Wenn der Netzwerkanruf beispielsweise 2 Sekunden dauert, bleibt jeder Thread 2 Sekunden lang hängen, ohne etwas anderes zu tun als zu warten.
Andererseits
WaitAll
blockiert der obige Code mit auch die Threads und Ihre Threads können keine anderen Arbeiten verarbeiten, bis der Vorgang endet.Empfohlener Ansatz
Ich würde es vorziehen, wenn
WhenAll
Ihre Operationen asynchron parallel ausgeführt werden.Um dies zu belegen, finden Sie hier einen detaillierten Blog-Beitrag, in dem alle Alternativen und ihre Vor- und Nachteile erläutert werden: Wie und wo gleichzeitige asynchrone E / A mit der ASP.NET-Web-API
quelle
WaitAll
blockiert auch die Threads" - blockiert er nicht nur einen Thread, den aufgerufenenWaitAll
?Ich war neugierig auf die Ergebnisse der in der Frage angegebenen Methoden sowie auf die akzeptierte Antwort und habe sie auf die Probe gestellt.
Hier ist der Code:
Und die daraus resultierende Ausgabe:
quelle
Da die von Ihnen aufgerufene API asynchron ist, macht die
Parallel.ForEach
Version wenig Sinn. Sie sollten.Wait
in derWaitAll
Version nicht verwenden, da dies die Parallelität verlieren würde. Eine andere Alternative, wenn der Aufrufer asynchron ist, ist die VerwendungTask.WhenAll
nach dem AusführenSelect
undToArray
zum Generieren des Array von Aufgaben. Eine zweite Alternative ist die Verwendung von Rx 2.0quelle
Sie können eine
Task.WhenAll
Funktion verwenden, mit der Sie n Aufgaben übergeben können.Task.WhenAll
gibt eine Aufgabe zurück, dieTask.WhenAll
vollständig ausgeführt wird, wenn alle Aufgaben, die Sie übergeben haben, abgeschlossen sind. Sie müssen asynchron warten,Task.WhenAll
damit Sie Ihren UI-Thread nicht blockieren:quelle
Parallel.ForEach
erfordert eine Liste benutzerdefinierter Worker und eine nicht asynchroneAction
Ausführung für jeden Worker.Task.WaitAll
undTask.WhenAll
erfordern eineList<Task>
, die per Definition asynchron sind.Ich fand die Antwort von RiaanDP sehr nützlich, um den Unterschied zu verstehen, aber es muss korrigiert werden . Nicht genug Ruf, um auf seinen Kommentar zu antworten, daher meine eigene Antwort.
Parallel.ForEach
Die resultierende Ausgabe ist unten. Ausführungszeiten sind vergleichbar. Ich habe diesen Test ausgeführt, während mein Computer den wöchentlichen Antivirenscan durchführte. Durch Ändern der Reihenfolge der Tests wurden die Ausführungszeiten geändert.
quelle