2012-03-18 2 views
2

できるだけ早くデータをシリアルプロセスに戻すアプリケーションが重要ですが、そのデータを取得するソース。同様に、あるソースが他のソースよりも速い場合もありますが、どのソースを使用するかはわかりません。私はContinueWhenAny(...)を使用しています。継続するために終了する最初のタスクを待ってから呼び出しメソッドから戻ります。しかし、まずデータの有効性をチェックしてから、戻ってください(またはすべてのタスクが終了し、有効なデータを持っていない場合)。今すぐ最初に終了するタスクであれば、私のコードは無効なデータでも返します。タスク並列ライブラリを使用して複数のタスクを実行し、最初のプロセスの後で実際にデータを返すにはどうすればいいですか?

「ContinueWhenAny」のようなやり方がありますが、Task.Resultが特定の条件を満たす場合のみ、そうでない場合は最後のタスクが終了するまで次のタスクを待ちます。

また、1つの結果が有効であることを確認し、他のスレッドがキャンセルすることを確認する必要があります。この部分はすでにうまく動作しています。

 ResultObject result = null; 
     var tokenSource = new CancellationTokenSource(); 
     var tasks = listOfSources 
       .Select(i => Task.Factory.StartNew(
        () => 
         { 
          i.CancellationToken = tokenSource.Token; 
          //Database Call 
          return i.getData(inputparameters); 
         }, tokenSource.Token)); 

     Task.Factory.ContinueWhenAny(
       tasks.ToArray(), 
       firstCompleted => 
        { 
         //This is the "result" I need to validate before setting and canceling the other threads 
         result = firstCompleted.Result; 
         tokenSource.Cancel(); 
        }).Wait(); 
     return result; 

任意のアイデア:

現在、私のコードは、この(例外処理、ちょうどナットやボルトを剥奪)のように見えますか?私はContinueWhenAllを使いたくないので、最初の呼び出しが2秒かかり、10秒がかかる場合、最初の呼び出しが有効なデータを返す場合は2秒後にシリアルプロセスに戻ります。結果には有効なデータがあり、すべてのタスクが完了して無効な結果が返された場合にのみ無効なデータを返します。

--------- UPDATE ---- 素晴らしいアイデアをお寄せいただきありがとうございます。更新された(動作中の)コードは以下の通りであり、私のすべての要件を満たしています。ただし、このコードと前のコードの違いは、無効な結果自体を返す前のコードではなく、タスクが有効な結果を生成しない場合にこのコードがnull結果を返すことです。このバージョンを変更することも難しくありませんが、私はその目的のためにnullを返すことに完全に満足しています。

 ResultObject result = null; 
     var tokenSource = new CancellationTokenSource(); 
     var tasks = listOfSources 
       .Select(i => Task.Factory.StartNew(
        () => 
         { 
          i.CancellationToken = tokenSource.Token; 
          //Database Call 
          return i.getData(inputparameters); 
         }, tokenSource.Token)).ToArray(); 

     result = GetFirstValidResult(tokenSource,tasks); 

     return result; 


    private ResultObject GetFirstValidResult(CancellationTokenSource tokenSource, Task<ResultObject>[] tasks) 
    { 
     ResultObject result = null; 
     Task.Factory.ContinueWhenAny(
      tasks, 
      firstCompleted => 
       { 
        var testResult = firstCompleted.Result; 
        if(testResult != null && testResult.IsValid()) 
        { 
         result = testResult; 
         tokenSource.Cancel(); 
        } 
        else 
        { 
         var remainingTasks = tasks.Except(new[]{firstCompleted}).ToArray(); 
         if(remainingTasks.Any()) 
         { 
          result = GetFirstValidResult(tokenSource, remainingTasks); 
         } 
        } 
       }).Wait(); 
     return result; 
    } 

答えて

4

あなたfirstCompletedコールバックは、結果を確認し、その結果が違法である場合には残りのタスクにContinueWhenAnyを呼ぶならばまあ、あなたが行うことと思います。

いつものように、ZeroMQをご覧ください。タスクを起動し、結果が正当なものであれば各タスクに出力キューにメッセージを書き込ませます。メインスレッドはキュー上でブロックし、有効なメッセージがあるとき、またはすべてのタスクが既に終了したときに戻る。

+0

ありがとうございます!私は単体テストでこのケースをテストしているので、動作している限りこれをチェックしてマークします。 –

+1

素晴らしい作品です!私はContinueWhenAnyロジックをそれ自身の関数に移さなければならなかったので、それ以上のタスクがなくなるまで再帰的に呼び出すことができました。私はそれを見たい人のための質問に更新されたコードを含めます。 –

関連する問題