2013-04-07 3 views
6

У меня есть 3 задачи, которые должны запускаться параллельно. Мне нужно подождать все 3, а затем продолжить обработку результатов. Так что-то вроде:Как обрабатывать частичный успех в партии задач?

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

Это прекрасно работает, когда все 3 задания успешно завершены. Однако, если один из них терпит неудачу, я получаю исключение, которое пузырится вверх. Это не то, что я хочу. Если какая-либо из этих задач вызывает InvalidOperationException, я могу продолжить обработку, мне нужен только метод process, чтобы получить доступ к исключению, которое было выбрано.

Я понимаю, что могу выполнить try...catch в задачах, но это не похоже на хак. Помимо того, что это семантически некорректно (задача DID не удалась - она ​​не должна возвращаться успешно), если я пошел с таким подходом, так как результат может быть успешным ИЛИ вернуть исключение, мне пришлось бы возвращать настраиваемый тип. Объект Task<T>, однако, уже предоставляет канал Exception, поэтому я бы предпочел не выполнять двойную работу и просто использовать то, что уже присутствует.

+0

Если вы правильно поняли, вам нужно что-то вроде 'var combinationTask = Task.WhenAll (...); ожидание integerTask.IgnoreExceptions(); процесс возврата (mixedTask); '? Где 'IgnoreExceptions()' позволит «подождать» сбоя «Задача», не вызывая исключения. Или что именно должны содержать «результаты»? – svick

+0

@svick - Я согласен, кажется, что результаты не могут быть согласованным типом. Моя мысль заключается в том, что мне нужно будет работать непосредственно с объектом Task здесь, а не использовать асинхронный/ожидающий фасад. Если я могу гарантировать, что все задачи выполняются до завершения независимо от ошибок, я могу работать с этими объектами задачи, но я не уверен, как это сделать. –

+0

@svick - это 'IgnoreExceptions()' что-то существующее? Я не могу найти его. –

ответ

2

Вы можете обрабатывать этот случай, как в моем примере ниже:

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

, так что если task1 занимает 1 секунду, то task2 занимает 2, а task3 занимает 3, а task1 выдает ошибку. Стала бы задача2 и задача3 в этой ситуации? Похоже, их отменяют. –

+0

Кроме того, как я мог бы узнать в этой ситуации, какая задача бросила исключение –

+0

@GeorgeMauer Как они могут быть отменены? 'Задача' не может быть отменена так же, как это делается,' CancellationTokenSource' и 'WhenAll()' не имеет доступа к чему-либо подобному. – svick

1

Если я вас правильно понимаю, что вы ищете это?

var tasks = new[] { task1, task2, task3 }; 
try { await Task.WhenAll(tasks); } catch (...) { } 
return process(tasks); 
Смежные вопросы