401 Stimmen

Das Ausführen mehrerer asynchroner Aufgaben und das Warten darauf, dass diese alle abgeschlossen sind

Ich muss mehrere asynchrone Aufgaben in einer Konsolenanwendung ausführen und warten, bis sie alle abgeschlossen sind, bevor ich weiter verarbeite.

Es gibt viele Artikel dazu, aber je mehr ich lese, desto verwirrter werde ich. Ich habe die grundlegenden Prinzipien der Task-Bibliothek gelesen und verstanden, aber offensichtlich fehlt mir irgendwo eine Verbindung.

Ich verstehe, dass es möglich ist, Aufgaben zu verketten, so dass sie nach dem Abschluss einer anderen beginnen (was im Grunde das Szenario für alle Artikel ist, die ich gelesen habe), aber ich möchte alle meine Aufgaben gleichzeitig ausführen lassen und ich möchte wissen, wenn sie alle abgeschlossen sind.

Was ist die einfachste Umsetzung für ein Szenario wie dieses?

8voto

Möchten Sie die Tasks verketten oder können sie parallel aufgerufen werden?

Zum Verketten
Einfach etwas wie das hier machen

Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);

und vergessen Sie nicht, das vorherige Task-Instanz in jedem ContinueWith zu überprüfen, da sie möglicherweise fehlerhaft ist.

Für den parallelen Ansatz
Die einfachste Methode, die ich gefunden habe: Parallel.Invoke Ansonsten gibt es Task.WaitAll oder Sie können sogar WaitHandles verwenden, um einen Countdown auf Null verbleibende Aktionen durchzuführen (Moment mal, es gibt eine neue Klasse: CountdownEvent), oder ...

6voto

DalSoft Punkte 9849

So mache ich es mit einem Array Func<>:

var tasks = new Func[]
{
   () => myAsyncWork1(),
   () => myAsyncWork2(),
   () => myAsyncWork3()
};

await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Asynchron    
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Oder WaitAll für synchron

1voto

Soroosh Punkte 11

Sie möchten vielleicht einen Blick auf den unten stehenden Link werfen, der die bewährte Praxis für await async erklärt. https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/async-scenarios

Verwenden Sie das...       Anstatt dessen...   Wenn Sie dies möchten...
await                        Task.Wait  
                           Task.Result          Abrufen des Ergebnisses einer Hintergrundaufgabe
await Task.WhenAny           Task.WaitAny         Warten auf den Abschluss einer beliebigen Aufgabe
await Task.WhenAll           Task.WaitAll          Warten auf den Abschluss aller Aufgaben
await Task.Delay             Thread.Sleep         Warten für eine bestimmte Zeit

-1voto

sayah imad Punkte 1469

Ich habe ein Stück Code vorbereitet, um Ihnen zu zeigen, wie Sie die Aufgabe für einige dieser Szenarien verwenden können.

    // Methode zum Ausführen von Aufgaben parallel 
    public async Task RunMultipleTaskParallel(Task[] tasks) {

        await Task.WhenAll(tasks);
    }
    // Methode zum sequenziellen Ausführen von Aufgaben 
    public async Task RunMultipleTaskOneByOne(Task[] tasks)
    {
        for (int i = 0; i < tasks.Length - 1; i++)
            await tasks[i];
    }
    // Methode zum parallelen Ausführen von i Aufgaben
    public async Task RunMultipleTaskParallel(Task[] tasks, int i)
    {
        var countTask = tasks.Length;
        var remainTasks = 0;
        do
        {
            int toTake = (countTask < i) ? countTask : i;
            var limitedTasks = tasks.Skip(remainTasks)
                                    .Take(toTake);
            remainTasks += toTake;
            await RunMultipleTaskParallel(limitedTasks.ToArray());
        } while (remainTasks < countTask);
    }

-1voto

user2023861 Punkte 7454

Es sollte eine prägnantere Lösung als die akzeptierte Antwort geben. Es sollte nicht drei Schritte dauern, um mehrere Aufgaben gleichzeitig auszuführen und ihre Ergebnisse zu erhalten.

  1. Aufgaben erstellen
  2. await Task.WhenAll(tasks)
  3. Aufgabenergebnisse abrufen (z. B. task1.Result)

Hier ist eine Methode, die dies auf zwei Schritte reduziert:

    public async Task> WhenAllGeneric(Task task1, Task task2)
    {
        await Task.WhenAll(task1, task2);
        return Tuple.Create(task1.Result, task2.Result);
    }

Sie können es wie folgt verwenden:

var taskResults = await Task.WhenAll(DoWorkAsync(), DoMoreWorkAsync());
var DoWorkResult = taskResults.Result.Item1;
var DoMoreWorkResult = taskResults.Result.Item2;

Dies beseitigt die Notwendigkeit für temporäre Task-Variablen. Das Problem bei der Verwendung dieser Methode ist, dass sie zwar für zwei Aufgaben funktioniert, aber für drei Aufgaben oder eine beliebige Anzahl von Aufgaben aktualisiert werden müsste. Außerdem funktioniert es nicht gut, wenn eine der Aufgaben nichts zurückgibt. Eigentlich sollte die .Net-Bibliothek etwas bereitstellen können, das dies kann

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