520 Stimmen

Verwendung von async/await für mehrere Aufgaben

Ich verwende einen API-Client, der vollständig asynchron ist, d. h., jeder Vorgang gibt entweder Task oder Task<T> z.B:

static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
    await client.DeletePost(siteId, postId); // call API client
    Console.WriteLine("Deleted post {0}.", siteId);
}

Mit der C# 5 async/await-Operatoren, was ist der richtige/effizienteste Weg, um mehrere Aufgaben zu starten und warten, bis sie alle zu beenden:

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 intern HttpClient verwendet, würde ich erwarten, dass dies 5 HTTP-Anforderungen sofort ausgeben und in die Konsole schreiben, wie jeder abgeschlossen ist.

6voto

AlexPavlov Punkte 267

Die Frage ist 10 Jahre alt und OP fragte nach C# 5.

Ab heute gibt es eine weitere Möglichkeit: Die Methode Parallel.ForEachAsync, die in .NET 6 eingeführt wurde.

Hier ist ein Beispiel auf der Grundlage des Codes des Auftraggebers:

int[] ids = new[] { 1, 2, 3, 4, 5 };
await Parallel.ForEachAsync(ids, async (i,token) => await DoSomething(1, i, blogClient));

Dies ist völlig asynchron und blockiert keine Threads.

Außerdem ist es möglicherweise besser als die Ansätze Task.WaitAll und Task.WhenAll, weil sie die Anzahl der parallel laufenden Threads nicht begrenzen. Wenn Sie also ein großes Array haben, kann es Ihren gesamten RAM-Speicher aufbrauchen. Mit Parallel.ForEachAsync können Sie den Grad der Parallelität wie folgt angeben:

var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };

await Parallel.ForEachAsync(ids, options, async (i,token) => await DoSomething(1, i, blogClient));

Auf diese Weise haben Sie nur 4 parallel laufende Threads.

5voto

Feng Jiang Punkte 1525

Alle Antworten beziehen sich auf die Ausführung der gleichen Funktion.

Der folgende Code funktioniert für den Aufruf verschiedener Funktionen. Setzen Sie einfach Ihre reguläre Task.Run() innerhalb eines Arrays und rufen mit Task.WhenAll() :

await Task.WhenAll(new Task[] { 
    Task.Run(() => Func1(args)),
    Task.Run(() => Func2(args))
});

1voto

Ygalbel Punkte 4854

Ich möchte nur zu allen großartigen Antworten oben hinzufügen, dass es eine gute Praxis ist, wenn man eine Bibliothek schreibt, die ConfigureAwait(false) und erhalten eine bessere Leistung, wie gesagt hier .

Dieser Ausschnitt scheint also besser zu sein:

 public static async Task DoWork() 
 {
     int[] ids = new[] { 1, 2, 3, 4, 5 };
     await Task.WhenAll(ids.Select(i => DoSomething(1, i))).ConfigureAwait(false);
 }

Ein vollständiger Fiddle-Link hier .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X