4

私は、他のいくつかの Web サービスを順番に呼び出している WCF サービスを持っています。サービスは優先順に並べられますが、並行して呼び出されます。各サービスは true または false で応答し、すべての応答が受信されると、最も好ましい陽性がクライアントに返されます。

ただし、この間の任意の時点で、最も優先されるサービスが肯定的に応答する可能性があります。この時点で他のサービスのクエリを続行しても意味がないため、実行をキャンセルしてクライアントに結果を返したいと考えています。

私にできることはそれだけです:

// Use parallelOptions to store the cancellation token
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Parallel.ForEach<IntegrationObj>(externalServices, po, x =>
{
    try
    {
        // Send requests
        SendExternalRequest(x);
        po.CancellationToken.ThrowIfCancellationRequested();
    }
    catch (OperationCanceledException e)
    {
        /// Don't throw an exception if the loop was cancelled
    }
    catch (Exception e)
    {
        LogError(e.Message);
    }
});
if (positiveResponses.Count > 0) {
    // Get the most preferred positive response and send it back to the client
    res = positiveResponses.Where(
        x => x.ID == PreferredServiceID)
        .FirstOrDefault();
}
return res;

上記のコードは私のコードの非常に単純化されたバージョンですが、基本的には各応答をチェックして、現在最も優先されるサービスであるかどうかを確認します。その場合、ループをキャンセルします。

ただし...この方法でループをキャンセルすると、ループを終了する前に、既に呼び出されたサービスが終了するのを待ちます。いずれかのサービスがタイムアウトになる可能性は十分にありますが、もちろんこれは否定的なものとして扱われます。そのうちの 1 つでもタイムアウトになると、応答時間が 10 秒長くなります。

私がやりたいことは、次のいずれかです。

  1. 優先サービスをクライアントに返し、すでに開始されているサービスからの応答の処理を続行します (これは、これらのサービスの正/負の割合を知るための純粋なログ記録のためです)。
  2. ループを即座にキャンセルし、残りの応答を忘れます。理想的には、これを行いたくありません。これは、肯定的に応答したサービスがそのように記録されず、好みの評価に影響することを意味するためです。

だから私の質問はこれです:

私が達成したいことは可能ですか?私は、parallel.foreach がこの仕事に最適なツールではないかもしれないこと、またはクライアントに応答した後に応答をログに記録できないかもしれないことを認識しています。最も重要な要件は、「勝者」がすでに選択されている場合に、サービスが応答するのを待たずに、クライアントが迅速な応答を受信することです。

4

1 に答える 1

1

現在の設定方法では、すべてのサービスが並行して開始されますが、チェックはすべてのサービスが終了した後にのみ実行されるようにプログラムされています。
foreach アプローチに固執したい場合は、 foreach 内に if 条件を書くことができます。そうすれば、サービスが最初に終了した場合、肯定応答のチェックが直接実行され、それに応じて対応できます (値を返す/他のものを殺す)。
このアプローチには、注意が必要なスレッドの安全性がさらにあることに注意してください(サービスの1つが書き込もうとしている可能性のあるリストからの読み取り)。2 つのサービスが同時に終了する可能性もあるため、if ステートメントが 2 回起動します。

foreach アプローチの代替手段は、サービスごとにスレッドを作成し、すべてのスレッドをリストに入れ、すべてのスレッドを開始した直後に while ループを開始して、終了したサービスを (もちろんスリープ状態で) チェックし続けることです。このようにして、while ループを中断することで、他のスレッドがまだ実行されている間に値を返すことができます。

于 2012-04-26T13:41:28.253 に答える