Are those lines behaving exactly the same (Including Exceptionhandling via AggregateException)?
Task.WhenAll(taskList).Wait()
Task.WaitAll(taskList)
Thanks
Are those lines behaving exactly the same (Including Exceptionhandling via AggregateException)?
Task.WhenAll(taskList).Wait()
Task.WaitAll(taskList)
Thanks
Let's find out by experimentation:
var task1 = Task.FromResult(13);
var task2 = Task.FromCanceled<int>(new CancellationToken(true));
var task3 = Task.FromCanceled<int>(new CancellationToken(true));
var task4 = Task.FromException<int>(new ApplicationException());
var task5 = Task.FromException<int>(new OverflowException());
Test("Successful+Canceled+Canceled", new[] { task1, task2, task3 });
Test("Successful+Failed+Failed", new[] { task1, task4, task5 });
Test("Successful+Canceled+Failed+Failed", new[] { task1, task2, task4, task5 });
Test("Successful+Canceled+Canceled+Failed", new[] { task1, task2, task3, task4 });
static void Test(string title, Task<int>[] tasks)
{
Console.WriteLine();
Console.WriteLine(title);
try { Task.WaitAll(tasks); }
catch (AggregateException ex)
{
Console.WriteLine($"WaitAll(): {ToString(ex)}");
}
try { Task.WhenAll(tasks).Wait(); }
catch (AggregateException ex)
{
Console.WriteLine($"WhenAll.Wait(): {ToString(ex)}");
}
}
static string ToString(AggregateException aex) {
return $"({aex.InnerExceptions.Count}) " +
String.Join(", ", aex.InnerExceptions.Select(ex => ex.GetType().Name));
}
Output:
Successful+Canceled+Canceled
WaitAll(): (2) TaskCanceledException, TaskCanceledException
WhenAll.Wait(): (1) TaskCanceledException
Successful+Failed+Failed
WaitAll(): (2) ApplicationException, OverflowException
WhenAll.Wait(): (2) ApplicationException, OverflowException
Successful+Canceled+Failed+Failed
WaitAll(): (3) TaskCanceledException, ApplicationException, OverflowException
WhenAll.Wait(): (2) ApplicationException, OverflowException
Successful+Canceled+Canceled+Failed
WaitAll(): (3) TaskCanceledException, TaskCanceledException, ApplicationException
WhenAll.Wait(): (1) ApplicationException
What we see is that the Task.WaitAll()
method propagates the exceptions of the tasks as they are, while the Task.WhenAll()
.Wait()
approach propagates only a single TaskCanceledException
, and only when no other type of exception has occurred.
It should also be mentioned that with the Task.WaitAll
you get more options out of the box, like millisecondsTimeout
, or cancellationToken
, or both.