web-dev-qa-db-fra.com

WaitAll vs WhenAll

Quelle est la différence entre Task.WaitAll() et Task.WhenAll() du CTP Async? Pouvez-vous fournir un exemple de code pour illustrer les différents cas d'utilisation?

290
Yaron Levi

Task.WaitAll bloque le thread actuel jusqu'à ce que tout soit terminé.

Task.WhenAll renvoie une tâche qui représente l'action d'attendre que tout soit terminé.

Cela signifie que depuis une méthode asynchrone, vous pouvez utiliser:

await Task.WhenAll(tasks);

... ce qui signifie que votre méthode continuera quand tout sera terminé, mais vous ne ferez rien pour que traîner jusqu'à ce que ça dure.

444
Jon Skeet

Alors que la réponse de JonSkeet explique la différence de manière généralement excellente, la plus grande différence pratique est traitement des exceptions. EDIT: D'accord - ce n'est pas la plus grande différence pratique, c'est une différence.

Task.WaitAll lève un AggregateException lorsqu'une tâche est lancée et vous pouvez examiner toutes les exceptions renvoyées. La await dans await Task.WhenAll décompresse la AggregateException et 'renvoie' uniquement la première exception.

Lorsque le programme ci-dessous s'exécute avec await Task.WhenAll(taskArray), la sortie est la suivante.

19/11/2016 12:18:37 AM: Task 1 started
19/11/2016 12:18:37 AM: Task 3 started
19/11/2016 12:18:37 AM: Task 2 started
Caught Exception in Main at 19/11/2016 12:18:40 AM: Task 1 throwing at 19/11/2016 12:18:38 AM
Done.

Lorsque le programme ci-dessous est exécuté avec Task.WaitAll(taskArray), la sortie est la suivante.

19/11/2016 12:19:29 AM: Task 1 started
19/11/2016 12:19:29 AM: Task 2 started
19/11/2016 12:19:29 AM: Task 3 started
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 1 throwing at 19/11/2016 12:19:30 AM
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 2 throwing at 19/11/2016 12:19:31 AM
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 3 throwing at 19/11/2016 12:19:32 AM
Done.

Le programme:

class MyAmazingProgram
{
    public class CustomException : Exception
    {
        public CustomException(String message) : base(message)
        { }
    }

    static void WaitAndThrow(int id, int waitInMs)
    {
        Console.WriteLine($"{DateTime.UtcNow}: Task {id} started");

        Thread.Sleep(waitInMs);
        throw new CustomException($"Task {id} throwing at {DateTime.UtcNow}");
    }

    static void Main(string[] args)
    {
        Task.Run(async () =>
        {
            await MyAmazingMethodAsync();
        }).Wait();

    }

    static async Task MyAmazingMethodAsync()
    {
        try
        {
            Task[] taskArray = { Task.Factory.StartNew(() => WaitAndThrow(1, 1000)),
                                 Task.Factory.StartNew(() => WaitAndThrow(2, 2000)),
                                 Task.Factory.StartNew(() => WaitAndThrow(3, 3000)) };

            Task.WaitAll(taskArray);
            //await Task.WhenAll(taskArray);
            Console.WriteLine("This isn't going to happen");
        }
        catch (AggregateException ex)
        {
            foreach (var inner in ex.InnerExceptions)
            {
                Console.WriteLine($"Caught AggregateException in Main at {DateTime.UtcNow}: " + inner.Message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Caught Exception in Main at {DateTime.UtcNow}: " + ex.Message);
        }
        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}
42
tymtam

À titre d’exemple, si vous avez une tâche, le thread de l’interface utilisateur exécute une action (par exemple, une tâche représentant une animation dans un storyboard) si vous Task.WaitAll(), le thread d’interface utilisateur est bloqué et l’interface utilisateur ne s'affiche jamais. mis à jour. Si vous utilisez await Task.WhenAll(), le thread d'interface utilisateur n'est pas bloqué et l'interface utilisateur sera mise à jour.

17
J. Long

Que font-ils:

  • En interne, les deux font la même chose.

Quelle est la différence:

  • WaitAll est un appel bloquant
  • WhenAll - not - le code continuera à s'exécuter

Utilisez lequel quand:

  • WaitAll quand ne peut pas continuer sans avoir le résultat
  • WhenAll quand quoi quoi être avisé, pas bloqué
4
i100