Exécution de plusieurs tâches asynchrones et attente de leur exécution

Je dois exécuter plusieurs tâches asynchrones dans une application console et attendre qu’elles soient toutes terminées avant de poursuivre le traitement.

Il y a beaucoup d’articles là-bas, mais je semble devenir plus confus au fur et à mesure que je lis. J’ai lu et compris les principes de base de la bibliothèque de tâches, mais il me manque clairement un lien quelque part.

Je comprends qu’il est possible d’enchaîner les tâches pour qu’elles se terminent après les autres (ce qui est pratiquement le cas pour tous les articles que j’ai lus), mais je veux que toutes mes tâches soient exécutées en même temps et que je veuille ils sont tous terminés.

Quelle est l’implémentation la plus simple pour un scénario comme celui-ci?

    Les deux réponses ne mentionnaient pas le Task.WhenAll :

     var task1 = DoWorkAsync(); var task2 = DoMoreWorkAsync(); await Task.WhenAll(task1, task2); 

    La principale différence entre Task.WaitAll et Task.WhenAll est que le premier va bloquer (comme utiliser Wait sur une seule tâche) alors que le second ne le peut pas et peut être attendu, cédant le contrôle à l’appelant jusqu’à ce que toutes les tâches se terminent.

    Plus encore, la gestion des exceptions diffère:

    Task.WaitAll :

    Au moins une des instances de tâche a été annulée ou une exception a été générée lors de l’exécution d’au moins une des instances de tâche. Si une tâche a été annulée, l’exception AggregateException contient une exception OperationCanceledException dans sa collection InnerExceptions.

    Task.WhenAll :

    Si l’une des tâches fournies se termine dans un état défaillant, la tâche renvoyée se terminera également dans un état défectueux, où ses exceptions contiendront l’agrégation de l’ensemble des exceptions non emballées de chacune des tâches fournies.

    Si aucune des tâches fournies n’est défaillante mais qu’au moins l’une d’entre elles a été annulée, la tâche renvoyée se termine à l’état Annulé.

    Si aucune des tâches n’est défaillante et qu’aucune des tâches n’a été annulée, la tâche résultante se terminera dans l’état RanToCompletion. Si le tableau / énumérateur fourni ne contient aucune tâche, la tâche renvoyée passera immédiatement à un état RanToCompletion avant d’être renvoyée à l’appelant.

    Vous pouvez créer de nombreuses tâches comme:

     List TaskList = new List(); foreach(...) { var LastTask = new Task(SomeFunction); LastTask.Start(); TaskList.Add(LastTask); } Task.WaitAll(TaskList.ToArray()); 

    La meilleure option que j’ai vue est la méthode d’extension suivante:

     public static Task ForEachAsync(this IEnumerable sequence, Func action) { return Task.WhenAll(sequence.Select(action)); } 

    Appelez-le comme ceci:

     await sequence.ForEachAsync(item => item.SomethingAsync(blah)); 

    Ou avec un lambda async:

     await sequence.ForEachAsync(async item => { var more = await GetMoreAsync(item); await more.FrobbleAsync(); }); 

    Voulez-vous enchaîner les Task ou peuvent-elles être invoquées de manière parallèle?

    Pour chaîner
    Faites juste quelque chose comme

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

    et n’oubliez pas de vérifier l’instance de Task précédente dans chaque object ContinueWith car il pourrait être défaillant.

    Pour la manière parallèle
    La méthode la plus simple que j’ai Task.WaitAll : Parallel.Invoke Sinon, il y a Task.WaitAll ou vous pouvez même utiliser WaitHandle s pour faire un compte à rebours jusqu’à zéro actions (attendez, il y a une nouvelle classe: CountdownEvent ), ou …

    Vous pouvez utiliser WhenAll qui renverra une Task ou WaitAll qui n’a pas de type de retour et qui bloquera l’exécution de code supplémentaire à Thread.Sleep jusqu’à Thread.Sleep que toutes les tâches soient terminées, annulées ou défaillantes.

    entrer la description de l'image ici

    Exemple

     var tasks = new Task[] { await TaskOperationOne(), await TaskOperationTwo() }; Task.WaitAll(tasks); // or await Task.WhenAll(tasks); 

    Si vous souhaitez exécuter les tâches dans un ordre pratique, vous pouvez vous inspirer de cette réponse.

    Voici comment je le fais avec un tableau Func <> :

     var tasks = new Func[] { () => myAsyncWork1(), () => myAsyncWork2(), () => myAsyncWork3() }; await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync