web-dev-qa-db-ja.com

WaitAll vs WhenAll

非同期CTPのTask.WaitAll()Task.WhenAll()の違いは何ですか?さまざまなユースケースを説明するサンプルコードを提供できますか?

278
Yaron Levi

Task.WaitAllは、すべてが完了するまで現在のスレッドをブロックします。

Task.WhenAllは、すべてが完了するまで待機するアクションを表すtaskを返します。

これは、非同期メソッドから次を使用できることを意味します。

await Task.WhenAll(tasks);

...これは、すべてが完了したときにメソッドが続行されることを意味しますが、その時間までただぶらぶらするためにスレッドを縛ることはありません。

423
Jon Skeet

JonSkeetの答えは、私にとって典型的な優れた方法で違いを説明しますが、最大の実用的な違いは例外処理です。編集:合意-それは最大の実用的な違いではなく、違いです。

Task.WaitAllは、タスクのいずれかがスローされるとAggregateExceptionをスローし、スローされたすべての例外を調べることができます。 await Task.WhenAllawaitAggregateExceptionをアンラップし、最初の例外のみを「返します」。

以下のプログラムがawait Task.WhenAll(taskArray)で実行されると、出力は次のようになります。

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.

以下のプログラムをTask.WaitAll(taskArray)で実行すると、出力は次のようになります。

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.

プログラム:

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

違いの例として、タスクがある場合、Task.WaitAll()を使用するとUIスレッドで何かを実行します(たとえば、ストーリーボードのアニメーションを表すタスク)。UIスレッドはブロックされ、UIは更新されません。 await Task.WhenAll()を使用すると、UIスレッドはブロックされず、UIが更新されます。

16
J. Long

彼らは何をしますか:

  • 内部的には両方とも同じことをします。

違いは何ですか:

  • WaitAllはブロッキング呼び出しです
  • WhenAll-not-コードは実行を継続します

次の場合に使用します:

  • WaitAll結果なしで続行できない場合
  • WhenAll通知するだけで、ブロックしない場合
3
i100