Qual è la differenza tra Task.WaitAll()
e Task.WhenAll()
dal CTP Async? Potete fornire un codice di esempio per illustrare i diversi casi d'uso?
Qual è la differenza tra Task.WaitAll()
e Task.WhenAll()
dal CTP Async? Potete fornire un codice di esempio per illustrare i diversi casi d'uso?
Risposte:
Task.WaitAll
blocca il thread corrente fino al completamento di tutto.
Task.WhenAll
restituisce un'attività che rappresenta l'azione dell'attesa fino al completamento di tutto.
Ciò significa che da un metodo asincrono è possibile utilizzare:
await Task.WhenAll(tasks);
... il che significa che il tuo metodo continuerà quando tutto sarà completato, ma non legherai un thread per restare in attesa fino a quel momento.
WhenAll
, ma non è lo stesso che bloccare il thread.
Mentre la risposta di JonSkeet spiega la differenza in un modo tipicamente eccellente, c'è un'altra differenza: la gestione delle eccezioni .
Task.WaitAll
genera un AggregateException
momento in cui viene eseguita una delle attività e puoi esaminare tutte le eccezioni generate. In await
in await Task.WhenAll
riavvolge AggregateException
e "restituisce" solo la prima eccezione.
Quando il programma seguente viene eseguito con await Task.WhenAll(taskArray)
l'output è il seguente.
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.
Quando il programma seguente viene eseguito con Task.WaitAll(taskArray)
l'output è il seguente.
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.
Il programma:
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
, non una differenza tra i due metodi. Entrambi propagano un AggregateException
, lanciando direttamente o attraverso una proprietà (la Task.Exception
proprietà).
Come esempio della differenza: se hai un'attività, fa qualcosa con il thread dell'interfaccia utente (ad esempio un'attività che rappresenta un'animazione in uno storyboard) se Task.WaitAll()
il thread dell'interfaccia utente viene bloccato e l'interfaccia utente non viene mai aggiornata. se lo usi, await Task.WhenAll()
il thread dell'interfaccia utente non viene bloccato e l'interfaccia utente verrà aggiornata.
Cosa fanno:
Qual è la differenza:
Utilizzare quale quando:
WaitAll
come ho capito.
Task.WaitAll
dopo aver fatto qualche altro lavoro? Voglio dire, invece di chiamarlo subito dopo aver iniziato i tuoi compiti.