2013-04-07 17 views
6

Mam 3 zadania, które powinny działać równolegle. Muszę czekać na wszystkie 3, a następnie kontynuować przetwarzanie ich wyników. Tak coś takiego:Jak radzić sobie z częściowym sukcesem w grupie zadań?

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

Działa to dobrze, gdy wszystkie 3 zadania zakończą się powodzeniem. Jeśli jednak któryś z nich zawiedzie, otrzymuję wyjątek, który powoduje bąbelki na całej linii. Nie tego chcę. Jeśli którekolwiek z tych zadań rzuca InvalidOperationException mogę kontynuować przetwarzanie, po prostu potrzebuję metody process, aby uzyskać dostęp do wyjątku, który został zgłoszony.

Zdaję sobie sprawę, że mogę try...catch w ramach zadań, ale to nie wydaje się być hack. Poza tym, że nie jest to semantycznie niepoprawne (zadanie DID nie powiodło się - nie powinno powracać pomyślnie), jeśli zastosowałem to podejście, ponieważ wynik może się powieść LUB zwróci wyjątek, musiałbym zwrócić niestandardowy typ. Obiekt Task<T> już jednak ujawnia kanał wyjątków, więc wolałbym nie wykonywać podwójnego obowiązku i po prostu użyć tego, co już jest.

+0

Jeśli dobrze rozumiem, chcesz coś jak 'var combinedTask = Task.WhenAll (...); czekać na combinedTask.IgnoreExceptions(); proces powrotu (combinedTask); '? Gdzie 'IgnoreExceptions()' umożliwiałoby 'czekanie' na błędne' Zadanie' bez wyrzucania wyjątku. Albo co dokładnie powinno zawierać "wyniki"? – svick

+0

@svick - Zgadzam się, wydaje się, że wyniki nie mogą być spójne. Moją myślą jest, że będę musiał pracować bezpośrednio z obiektem Task tutaj i nie używać fasady async/await. Jeśli mogę zagwarantować, że wszystkie zadania będą wykonywane do końca bez względu na błędy, będę mógł pracować z tymi obiektami zadań, ale nie jestem pewien, jak to zrobić. –

+0

@svick - jest 'IgnoreExceptions()' coś, co istnieje? Nie mogę tego znaleźć. –

Odpowiedz

2

można obsługiwać tę sprawę tak jak w moim przykładzie poniżej:

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

, więc jeśli zadanie 1 trwa 1 sekundę, zadanie 2 zajmuje 2, a zadanie 3: 3, a zadanie 1 - błąd. Czy w tej sytuacji zadania 2 i zadania 3 nadal będą kompletne? Wygląda na to, że zostaną anulowani. –

+0

Ponadto, skąd mam wiedzieć w tej sytuacji, które zadanie rzuciło wyjątek? –

+0

@GeorgeMauer Jak można je anulować? 'Zadanie' nie może zostać anulowane, tak jak w przypadku 'CancellationTokenSource' i' WhenAll() 'nie ma dostępu do niczego podobnego. – svick

1

Jeśli rozumiem zostanie poprawnie, czego szukasz to?

var tasks = new[] { task1, task2, task3 }; 
try { await Task.WhenAll(tasks); } catch (...) { } 
return process(tasks); 
Powiązane problemy