2013-04-07 10 views
6

Ho 3 compiti che dovrebbero essere eseguiti in parallelo. Devo aspettare tutti e 3 e poi continuare ad elaborare i loro risultati. Quindi qualcosa tipo:Come gestire il successo parziale in un gruppo di attività?

var results = await Task.WhenAll(task1, task2, task3); 
return process(results); 

Funziona bene quando tutte e 3 le attività vengono completate correttamente. Tuttavia, se uno di questi fallisce, ricevo un'eccezione che bolle fino in fondo. Questo non è quello che voglio. Se una di queste attività genera un InvalidOperationException, posso continuare l'elaborazione, ho solo bisogno del metodo process per avere accesso all'eccezione generata.

Mi rendo conto che posso eseguire il comando try...catch all'interno delle attività, ma non sembra che sarebbe un trucco. Oltre ad essere semanticamente scorretto (l'attività DID non riesce - non dovrebbe tornare con successo), se sono andato con questo approccio, poiché il risultato può essere efficace O restituire un'eccezione, dovrei restituire un tipo personalizzato. L'oggetto Task<T> tuttavia espone già un canale Exception, quindi preferirei non fare double-duty e usare solo ciò che è già presente.

+0

Se ho capito bene, vuoi qualcosa come 'var combinedTask = Task.WhenAll (...); attendo combinedTask.IgnoreExceptions(); processo di ritorno (combinedTask); '? Dove 'IgnoreExceptions()' renderebbe possibile "attendere" un 'task' fasullo senza generare un'eccezione. O cosa dovrebbero contenere esattamente i risultati? – svick

+0

@svick - Sono d'accordo, sembra che i risultati non possano essere un tipo coerente. Il mio pensiero è che avrei bisogno di lavorare direttamente con l'oggetto Task qui e non usare la facciata async/await. Se posso garantire che tutte le attività siano eseguite fino al completamento, indipendentemente dagli errori, posso lavorare con questi oggetti task, ma non sono sicuro di come farlo. –

+0

@svick - è 'IgnoreExceptions()' qualcosa che esiste? Non riesco a trovarlo –

risposta

2

È possibile gestire questo caso come nel mio esempio qui sotto:

Task<T>[] tasks = new Task<T>[] { task1, task2, task3 }; 

try 
{ 
    await Task.WhenAll(tasks); 
} 
catch(InvalidOperationException exception) // If you need to handle any other exception do it 
{ 
    // handle it if you wan to 
} 

// You can use task1.IsFauled to know if current task failed, 
// and you can use task1.Exception to know why it failed 

return process(tasks.Where(t => !t.IsFauled).ToArray()); 
+0

quindi se task1 richiede 1 secondo per l'esecuzione, task2 richiede 2 e task3 richiede 3 e task1 genera un errore. Task2 e task3 sarebbero ancora completi in questa situazione? Sembra che verrebbero cancellati. –

+0

Inoltre, come faccio a sapere in questa situazione quale task ha lanciato l'eccezione –

+0

@GeorgeMauer Come possono essere cancellati? 'Task' non può essere cancellato in questo modo, ciò avviene' CancellationTokenSource' e 'WhenAll()' non ha accesso a qualcosa di simile. – svick

1

Se ho capito bene, si sta cercando questo?

var tasks = new[] { task1, task2, task3 }; 
try { await Task.WhenAll(tasks); } catch (...) { } 
return process(tasks); 
Problemi correlati