6

私のコードは 4 つの関数を実行して、次のようなクラスに (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 を返すことはできませんが、すべてのスレッドを停止し、処理を停止して null を返すことができるようにしたいということです。どうすれば達成できますか?

4

3 に答える 3

8

Parallel.Invokeできるだけ早く終了するには、次の3つのことを行う必要があります。

  1. 最初のアクションとして、早期に終了するかどうかを検出するアクションをスケジュールします。その後、より早くスケジュールされるので(おそらく最初と同じですが、それは保証されません)、終了するかどうかがより早くわかります。
  2. AggregateExceptionエラーを検出し、 Jonの回答が示すようにをキャッチすると、例外をスローします。
  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。そうでない場合、これらのメソッドにトークンを渡すことは意味がありません。

于 2010-09-16T08:17:27.433 に答える
4

アクションから例外をスローし、キャッチAggregateExceptionインGetPerson(つまり、try/catch ブロックを配置Parallel.Invoke) し、それが正しい種類の例外であることを確認して、null を返すことができます。

これは、すべてのスレッドを停止することを除いて、すべてを満たします。キャンセル トークンを取得し始めない限り、既に実行中のタスクを簡単に停止できる可能性は低いと思います。これまでのタスクのいずれかが失敗したかどうかを示す値を保持することで、それ以上のタスクの実行を停止し、各タスクが開始前にそれをチェックするようにすることができます...やや醜いですが、機能します.boolean

ただし、代わりに「フル」タスクを使用するParallel.Invokeと、これらすべてがよりエレガントになると思います。

于 2010-09-16T06:37:35.130 に答える
2

Personとにかく最初にデータベースからロードする必要がありますか? あなたのコードは null で Web サービスを呼び出します。

ロジックが本当にシーケンシャルである場合は、シーケンシャルに実行し、意味のあることだけを並列に実行します。

于 2010-10-01T02:39:04.663 に答える