2010-09-16 2 views
5

Мой код Исключение работает 4 функции для заполнения информации (с использованием Invoke) для класса, такие как:Parallel.Invoke - обработка

class Person 
{ 
    int Age; 
    string name; 
    long ID; 
    bool isVegeterian 

    public static Person GetPerson(int LocalID) 
    { 
     Person person; 
     Parallel.Invoke(() => {GetAgeFromWebServiceX(person)}, 
         () => {GetNameFromWebServiceY(person)}, 
         () => {GetIDFromWebServiceZ(person)}, 
         () => 
         { 
          // connect to my database and get information if vegeterian (using LocalID) 
          .... 
          if (!person.isVegetrian) 
           return null 
          .... 
         }); 
    } 
} 

Мой вопрос: Я не могу вернуть нулевое значение, если он не вегетарианское, но я хочу, чтобы остановить все потоки, остановить обработку и просто вернуть null. Как это можно достичь?

ответ

4

Ну, вы можете бросить исключение из ваших действий, поймать AggregateException в GetPerson (то есть поставить попробовать/поймать блок вокруг Parallel.Invoke), проверьте, что является правильным видом исключения, и возвращать нуль.

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

Я подозреваю, что использование «полных» задач вместо Parallel.Invoke сделало бы все это более элегантным.

7

Для выхода из Parallel.Invoke как можно раньше, вы должны сделать три вещи:

  1. Schedule действие, которое определяет, хотите ли вы, чтобы выйти уже в первом действии. Затем он запланирован раньше (возможно, как первый, но это не гарантировано), поэтому вы скоро узнаете, хотите ли вы выйти.
  2. Выбросить исключение, если вы обнаружите ошибку и поймаете AggregateException, как показывает ответ Джона.
  3. Используйте маркеры отмены. Однако это имеет смысл только в том случае, если у вас есть возможность проверить их имущество IsCancellationRequested.

Ваш код будет выглядеть следующим образом:

var cts = new CancellationTokenSource(); 
try 
{ 
    Parallel.Invoke(
     new ParallelOptions { CancellationToken = cts.Token }, 
     () => 
     { 
      if (!person.IsVegetarian) 
      { 
       cts.Cancel(); 
       throw new PersonIsNotVegetarianException(); 
      } 
     }, 
     () => { GetAgeFromWebServiceX(person, cts.Token) }, 
     () => { GetNameFromWebServiceY(person, cts.Token) }, 
     () => { GetIDFromWebServiceZ(person, cts.Token) } 
    ); 
} 
catch (AggregateException e) 
{ 
    var cause = e.InnerExceptions[0]; 
    // Check if cause is a PersonIsNotVegetarianException. 
} 

Однако, как я уже сказал, отмена лексемы только имеет смысл, если вы можете проверить их. Таким образом, должна быть возможность внутри GetAgeFromWebServiceX проверить токен отмены и выйти рано, в противном случае передача токенов этим методам не имеет смысла.

1

Возможно, вам нужно сначала загрузить Person из базы данных? Так как ваш код вызывает веб-службы с нулевым значением.

Если ваша логика действительно последовательна, сделайте это последовательно и делайте только параллельно, что имеет смысл.

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