528 votes

WaitAll et WhenAll

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

758voto

Jon Skeet Points 692016

Task.WaitAll bloque le fil d'exécution actuel jusqu'à ce que tout soit terminé.

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

Cela signifie qu'à partir d'une méthode asynchrone, vous pouvez utiliser :

await Task.WhenAll(tasks);

... ce qui signifie que votre méthode se poursuivra lorsque tout sera terminé, mais que vous n'attacherez pas un fil pour le laisser traîner jusqu'à ce moment-là.

0 votes

Est-ce que cela suppose que toutes les tâches que vous attendez sont en fait en train de travailler sur un autre thread ?

1 votes

@VincePanuccio Pour autant que je sache, un nouveau fil de discussion sera utilisé pour chaque tâche si nécessaire le cadre obtiendra le contexte du code et, s'il s'agit d'une opération de longue durée, un nouveau thread sera probablement utilisé.

6 votes

Après de nombreuses lectures, il est clair que l'asynchronisme n'a rien à voir avec les threads. blog.stephencleary.com/2013/11/il-n'y-a-pas-de-fil.html

141voto

Tymek Points 1305

Si la réponse de JonSkeet explique la différence d'une manière typiquement excellente, il existe une autre différence : traitement des exceptions .

Task.WaitAll lance un AggregateException lorsque l'une des tâches est lancée et vous pouvez examiner toutes les exceptions lancées. Le site await en await Task.WhenAll déballe le AggregateException et ne "renvoie" que la première exception.

Lorsque le programme ci-dessous s'exécute avec await Task.WhenAll(taskArray) le résultat est le suivant.

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) le résultat est le suivant.

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();
    }
}

43voto

J. Long Points 271

À titre d'exemple de la différence, si vous avez une tâche qui fait quelque chose avec le fil de l'interface utilisateur (par exemple, une tâche qui représente une animation dans un Storyboard), si vous Task.WaitAll() alors le thread de l'interface utilisateur est bloqué et l'interface utilisateur n'est jamais mise à jour. si vous utilisez await Task.WhenAll() alors le thread de l'interface utilisateur n'est pas bloqué, et l'interface utilisateur sera mise à jour.

30voto

i100 Points 1929

Que font-ils ?

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

Quelle est la différence ?

  • WaitAll est un appel bloquant
  • Quand tout - non - le code continuera à s'exécuter

Utilisez lequel quand :

  • WaitAll quand on ne peut pas continuer sans avoir le résultat
  • Quand tout quand quoi juste être notifié, pas bloqué

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X