2017-01-25 13 views
2

各ループでParallelを停止するのに問題があります。Parallel.ForEachをすぐに停止

テーブルから取得した約40.000個のDataRowsのセットを反復処理しています。結果セットに100個のアイテムがあるとすぐにループを停止する必要があります。問題は、ParallelLoopStateでStopメソッドをトリガーすると、イテレーションが即座に停止せず、結果セットに矛盾が発生することです。

私は停止を押すとすぐに、私はすべてのスレッドを殺すことを確認する方法はありませんか?

List<DataRow> rows = new List<DataRow>(dataTable.Select()); 
    ConcurrentDictionary<string, object> resultSet = new ConcurrentDictionary<string, object>(); 

    rows.EachParallel(delegate (DataRow row, ParallelLoopState state) 
    { 
    if (!state.IsStopped) 
    { 
     using (SqlConnection sqlConnection = new SqlConnection(Global.ConnStr)) 
     { 
     sqlConnection.Open(); 

     //{ 
     // Do some processing....... 
     //}  

     var sourceKey = "key retrieved from processing"; 
     if (!resultSet.ContainsKey(sourceKey)) 
     { 
      object myCustomObj = new object(); 

      resultSet.AddOrUpdate(
      sourceKey, 
      myCustomObj, 
      (key, oldValue) => myCustomObj); 
     } 

     if (resultSet.Values.Count == 100) 
      state.Stop(); 
     } 
    } 
    }); 
+1

*なぜ* SQLコマンドを並列実行しようとしていますか?これにより、悪いクエリがより速く実行されることはありません。あなたの*実際の*問題は何ですか? –

+0

メソッド –

+4

BTW 40K行でのロックの使用は全くデータがありません。あなたが100だけを望むときには40Kのすべてを読み込みますが、バグです。なぜあなたは 'SELECT TOP 100'を使わないのですか? –

答えて

4

ParallelLoopState.StopのドキュメントページはStop()を呼び出すと開始から新しい反復を防ぐことができますと説明しています。既存の反復は中止されません。

Stop()IsStoppedプロパティをtrueに設定します。長時間実行される反復では、IsStoppedの値をチェックし、必要に応じて時期尚早に終了することができます。

これは、協調キャンセルと呼ばれ、スレッドを中止するよりはるかに優れています。スレッドを中止するのは高価で、クリーンアップが困難です。あなたの仕事をコミットしたいときにちょうどThreadAbort例外がスローされたらどうなるか想像してみてください。一方、

協同組合のキャンセルは

など他の状態とファイルをクリーンアップ、接続を閉じ、タスクは必要に応じてトランザクションをコミットまたは中止した後、正常に終了することができますさらに、 Parallelの処理は、タスクではなく、スレッドを使用していますデータの断片。これらのスレッドの1つは、並列操作を開始した元のスレッドです。中止はスレッドプールのスレッドを無駄にするだけでなく、メインスレッドを強制終了します。

これはバグではないかある - Parallelは、データ並列の問題ではなく、非同期実行を解決するためのものです。このシナリオでは、システムが適切な数のタスクを使用してデータを処理し、処理が完了したら続行することを望みます。

+0

"これは、スレッドを中止するよりはるかに優れた協調キャンセルと呼ばれています" - 確かに...同じことを必ずしも達成するわけではありません。ループ本体が主に1つの呼び出しで構成されている場合、長い時間がかかる(たとえば、大きなファイルをアップロードする)場合、トークンは無価値です。私が中止すれば、私は欲しいものを手に入れます。 –

+0

@EdS。並列処理を非同期IOと混同します。非同期IOメソッドの他に、打ち消しトークンと取り消しトークンがサポートされています。あなたは*あなた*データからHTTPサーバーを停止することはできません、あなたはそれが到着するのを待つことができます。応答ストリームからの読み取りを停止することができます。中止後に取り消しトークンを使用して接続をクリーンアップすることができます。 Thread.Abort –

+0

@EdSでこれらのことを行うことはできません。また、スレッドを使用してIOをブロックすると、タスクがなくても無駄になります。 Win32は、コールバック、非同期IOの完了ポート、および待機するイベントを提供します。 –

関連する問題