2010-11-18 3 views
20

У меня проблема с обработкой исключений и параллельными задачами.Task.WaitAll и исключения

Код, показанный ниже, запускает 2 задания и ждет их завершения. Моя проблема в том, что если задача выдает исключение, обработчик catch никогда не будет достигнут.

 List<Task> tasks = new List<Task>(); 
     try 
     {     
      tasks.Add(Task.Factory.StartNew(TaskMethod1)); 
      tasks.Add(Task.Factory.StartNew(TaskMethod2)); 

      var arr = tasks.ToArray();     
      Task.WaitAll(arr); 
     } 
     catch (AggregateException e) 
     { 
      // do something 
     } 

Однако, когда я использую следующий код для ожидания задач с таймаутом, исключение попадает.

while(!Task.WaitAll(arr,100)); 

Я, кажется, что-то не хватает, так как документация WaitAll описывает свою первую попытку быть правильным. Пожалуйста, помогите мне понять, почему он не работает.

+1

Что делают TaskMethod1 и TaskMethod2? Какой поток вы выполняете? Если бы вы могли превратить это в короткий, но * полный * пример (например, мой ответ), который действительно помог бы. –

ответ

21

Не удается воспроизвести это - она ​​отлично работает для меня:

using System; 
using System.Threading; 
using System.Threading.Tasks; 

class Test 
{ 
    static void Main() 
    { 
     Task t1 = Task.Factory.StartNew(() => Thread.Sleep(1000)); 
     Task t2 = Task.Factory.StartNew(() => { 
      Thread.Sleep(500); 
      throw new Exception("Oops"); 
     }); 

     try 
     { 
      Task.WaitAll(t1, t2); 
      Console.WriteLine("All done"); 
     } 
     catch (AggregateException) 
     { 
      Console.WriteLine("Something went wrong"); 
     } 
    } 
} 

Это печатает «Что-то пошло не так», как я ожидал.

Возможно ли, что одна из ваших задач еще не закончена? WaitAll действительно ждет завершения всех задач, даже если некоторые из них уже сработали.

+2

спасибо за ваш быстрый ответ Джон! Моя проблема заключалась в том, что другая задача зависит от неудавшейся задачи, поэтому она всегда будет ждать неудавшейся задачи. Моя идея заключалась в том, что исключение сразу же происходит, когда задача выходит из строя, что не так. Спасибо что подметил это. – thumbmunkeys

+5

@pivotnig - взгляните на «Создание континуумов» здесь, чтобы явно выразить зависимость - http://msdn.microsoft.com/en-us/library/dd537609.aspx –

+0

@thumbmunkeys не понимает, что это опубликовано. Это именно то, что я задал здесь: https://stackoverflow.com/q/47820918/695964 – KFL

9

Вот как я решил эту проблему, как упомянуто в комментариях на мой ответ/вопрос (выше):

Вызывающий ловит любые исключения, порождаемые задач координируется барьера, и сигналы других задач с принудительной отмены:

CancellationTokenSource cancelSignal = new CancellationTokenSource(); 
try 
{ 
    // do work 
    List<Task> workerTasks = new List<Task>(); 
    foreach (Worker w in someArray) 
    { 
     workerTasks.Add(w.DoAsyncWork(cancelSignal.Token); 
    } 
    while (!Task.WaitAll(workerTasks.ToArray(), 100, cancelSignal.Token)) ; 

} 
catch (Exception) 
{ 
    cancelSignal.Cancel(); 
    throw; 
} 
+1

Это хорошо. Никогда не реализовал этот вариант использования для «CancellationTokenSource». – trailmax

0

Я пытался создать вызов для каждого элемента в коллекции, оказавшейся что-то вроде этого:

var parent = Task.Factory.StartNew(() => { 
    foreach (var acct in AccountList) 
    { 
     var currAcctNo = acct.Number; 
     Task.Factory.StartNew(() => 
     { 
     MyLocalList.AddRange(ProcessThisAccount(currAcctNo)); 
     }, TaskCreationOptions.AttachedToParent); 
     Thread.Sleep(50); 
    } 
    }); 

Мне пришлось добавить Thread.Sleep после каждого добавления дочерней задачи, потому что, если бы я этого не сделал, процесс имел бы тенденцию перезаписывать currAcctNo следующей итерацией. У меня было бы 3 или 4 разных номера счета в моем списке, и когда он обрабатывался каждый, в вызове ProcessThisAccount будет отображаться последний номер учетной записи для всех вызовов. Как только я включу «Сон», процесс отлично работает.

+0

, которые могут быть интересны: http://stackoverflow.com/questions/5009181/parallel-foreach-vs-task-factory-startnew – thumbmunkeys

+0

Parallel.ForEach более эффективен? – Kiquenet

+0

Что этот ответ имеет отношение к исходному вопросу? здесь нет исключений – knocte

Смежные вопросы