Jaka jest różnica pomiędzy Task.WaitAll()
i Task.WhenAll()
od Async CTP? Czy możesz podać przykładowy kod ilustrujący różne przypadki użycia?
Jaka jest różnica pomiędzy Task.WaitAll()
i Task.WhenAll()
od Async CTP? Czy możesz podać przykładowy kod ilustrujący różne przypadki użycia?
Odpowiedzi:
Task.WaitAll
blokuje bieżący wątek, dopóki wszystko się nie zakończy.
Task.WhenAll
zwraca zadanie reprezentujące akcję czekania, aż wszystko się zakończy.
Oznacza to, że z metody asynchronicznej możesz użyć:
await Task.WhenAll(tasks);
... co oznacza, że twoja metoda będzie kontynuowana, gdy wszystko się skończy, ale do tego czasu nie będziesz wiązać nici, żeby się po prostu zawiesić.
WhenAll
, ale to nie to samo, co blokowanie wątku.
Podczas gdy odpowiedź JonSkeeta wyjaśnia różnicę w typowo doskonały sposób, istnieje jeszcze jedna różnica: obsługa wyjątków .
Task.WaitAll
rzuca AggregateException
kiedy rzuca dowolne z zadań i możesz sprawdzić wszystkie zgłoszone wyjątki. Opcja await
in await Task.WhenAll
rozpakowuje AggregateException
i „zwraca” tylko pierwszy wyjątek.
Gdy program poniżej zostanie wykonany z await Task.WhenAll(taskArray)
danymi wyjściowymi, jest on następujący.
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.
Gdy poniższy program jest wykonywany z Task.WaitAll(taskArray)
danymi wyjściowymi, jest on następujący.
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.
Program:
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();
}
}
await t1; await t2; await t3;
vsawait Task.WhenAll(t1,t2,t3);
await
, a nie różnicę między tymi dwiema metodami. Obie propagują AggregateException
, rzucając bezpośrednio lub przez właściwość ( Task.Exception
właściwość).
Jako przykład różnicy - jeśli masz zadanie, robi coś z wątkiem interfejsu użytkownika (np. Zadanie reprezentujące animację w serii ujęć), jeśli Task.WaitAll()
następnie wątek interfejsu jest zablokowany, a interfejs użytkownika nigdy nie jest aktualizowany. jeśli używasz, await Task.WhenAll()
to wątek interfejsu użytkownika nie jest blokowany, a interfejs użytkownika zostanie zaktualizowany.
Co oni robią:
Co za różnica:
Użyj, gdy:
WaitAll
jak rozumiem.
Task.WaitAll
po wykonaniu innej pracy? Mam na myśli, zamiast nazywać go zaraz po rozpoczęciu zadań.