10

For ループの並列処理の中断を調査しています。

これこれを読んだ後、 私はまだ質問があります:

私はこのコードを期待します:

 Parallel.For(0, 10, (i,state) =>  
     { 
                Console.WriteLine(i); if (i == 5) state.Break(); 
     }

最大で6 つの数字 (0..6)を生成します。彼はそれをしていないだけでなく、結果の長さが異なります:

02351486
013542
0135642

とてもうるさい。(Break() {after 5} はどこにあるの??)

だから私はmsdnを見ました

ブレークは、現在の反復の後に他の反復を実行する必要がないことをループに伝えるために使用できます。0 から 1000 まで並列に反復する for ループの 100 番目の反復から Break が呼び出された場合、100 未満の反復はすべて実行されますが、101 から 1000 までの反復は必要ありません。

Quesion #1 :

どの繰り返し?全体の反復カウンター ? またはスレッドごと?スレッドごとにあると確信しています。承認してください。

Question #2 :

Parallel + range partition (要素間で CPU コストが変わらないため) を使用していると仮定して、データをスレッド間で分割します。したがって、4 つのコア (およびそれらの間の完全な分割) がある場合:

core #1 got 0..250
core #2 got 251..500
core #3 got 501..750
core #4 got 751..1000

そのため、スレッドはいつかcore #1出会い、壊れます。value=100これが彼の反復番号になり 100ます。しかし、スレッドcore #4はより多くの量子を取得し、彼は900今です。彼は彼の反復をはるかに超えています。100'th彼は100未満のインデックスを持っていません!! -だから彼はそれらすべてを見せます。

私は正しいですか?それが私の例で5つ以上の要素を取得する理由ですか?

Question #3 :

いつ本当に壊れるの(i == 5)ですか?

ps

つまり、さあ!私がそうするときBreak()、私は物事のループを止めたいです。通常のForループで行うのとまったく同じです。

4

3 に答える 3

10

最大で 6 つの数字 (0..6) を生成します。

問題は、これが最大 6 個の数値を生成しないことです。

何が起こるかというと、インデックス 5 のループにヒットすると、「ブレーク」リクエストが送信されます。 Break()これにより、ループは値を処理しなくなります>5が、すべての値を処理します<5

ただし、すでに開始されている 5 より大きい値は引き続き処理されます。さまざまなインデックスが並行して実行されているため、順序付けされていないため、いくつかの値>5(例では 8 など) がまだ実行されているさまざまな実行が得られます。

どの繰り返し?全体の反復カウンター ? またはスレッドごと?スレッドごとにあると確信しています。承認してください。

これは Parallel.For に渡されるインデックスです。Break() はアイテムの処理を妨げませんが、100 までのすべてのアイテムが処理されることを保証しますが、100 を超えるアイテムは処理される場合とされない場合があります。

私は正しいですか?それが私の例で5つ以上の要素を取得する理由ですか?

はい。あなたが示したようにパーティショナーを使用すると、 を呼び出すとすぐに、Break()中断したアイテムを超えるアイテムはスケジュールされなくなります。ただし、すでにスケジュールされているアイテム (パーティション全体) は完全に処理されます。あなたの例では、これは常に 1000 個のアイテムすべてを処理する可能性が高いことを意味します。

(i == 5) のときに本当に壊れるにはどうすればよいですか?

あなたはそうですが、パラレルで実行すると、状況が変わります。ここでの実際の目標は何ですか?最初の 6 アイテム (0 ~ 5) のみを処理する場合は、LINQ クエリなどを使用してアイテムをループする前に、アイテムを制限する必要があります。これで、6 つのアイテムを処理してParallel.ForもしParallel.ForEachなくても、Break()心配することなく処理できます。

つまり、さあ!Break() を実行すると、ループが停止します。通常の For ループとまったく同じです。

物事をできるだけ早く止めたい場合は、Stop()代わりに使用する必要があります。これにより、すでに実行Break()中のアイテムが停止するのを防ぐことはできませんが、アイテムをスケジュールすることはなくなります (現在の位置よりも低いインデックスまたは列挙の前のものを含む)。

于 2012-10-08T15:17:12.433 に答える
6

0 から 1000 まで並列に反復する for ループの 100 回目の反復から Break が呼び出された場合

ループの 100 回目の繰り返しは、インデックス 99 を持つものであるとは限りません (実際にはそうではない可能性があります)。

スレッドは、不確定な順序で実行できます。.Break() 命令が検出されると、それ以上のループ反復は開始されません。正確にいつ発生するかは、特定の実行のスレッド スケジューリングの詳細によって異なります。

読むことを強くお勧めします

並列プログラミングのパターン

(Microsoft から無料の PDF)

TPL に入った設計上の決定事項と設計上のトレードオフを理解する。

于 2012-10-08T15:16:58.773 に答える
4

どの繰り返し?全体の反復カウンター ? またはスレッドごと?

スケジュールされた (またはまだスケジュールされていない) すべての反復をオフにします。

デリゲートが順不同で実行される可能性があることに注意してください。反復i == 5が 6 番目に実行されるという保証はなく、まれなケースを除いて、そうなる可能性はほとんどありません。

Q2: そうですか?

いいえ、スケジューリングはそれほど単純ではありません。むしろ、すべてのタスクがキューに入れられてから、キューが処理されます。ただし、スレッドはそれぞれ、他のスレッドからスチールするときに空になるまで独自のキューを使用します。これでは、どのスレッドがどのデリゲートを処理するかを予測する方法はありません。

デリゲートが十分に自明である場合、元の呼び出しスレッドですべて処理される可能性があります (他のスレッドが作業を盗む機会はありません)。

Q3: (i == 5) の場合、どのように本当に壊れますか?

線形の (特定の) 処理が必要な場合は、同時に使用しないでください。

メソッドは、Break投機的実行をサポートするためにあります。さまざまな方法を試し、いずれかが完了したらすぐに停止します。

于 2012-10-08T15:21:55.903 に答える