5

実行が遅れた場合に、PLINQ を使用して並列処理がどのように機能するかを理解しようとしています。簡単な例を次に示します。

string[] words = { "believe", "receipt", "relief", "field" };
bool result = words.AsParallel().Any(w => w.Contains("ei"));

LINQ では、残りの値のクエリを実行せずに、実行が「領収書」値に到達して true を返すことを期待します。

これを並行して行うと、「受領」の結果が返される前に「救済」の評価が開始されている可能性があります。しかし、クエリが「受信」が真の結果をもたらすことを認識したら、他のスレッドはすぐに譲歩しますか?

私の場合、これは重要です。「any」テストは非常にコストがかかる可能性があり、他のタスクを実行するためにプロセッサを解放したいからです。

4

1 に答える 1

5

残念ながら、他のスレッドはすぐに「譲歩」しません。

有効な要素が見つかるとすぐAny()に、PLINQ スケジューラは新しい要素をチェックするために新しいスレッドのスケジューリングを停止します。既存のパーティショナーもキャンセル リクエストを受け取ります。これにより、それらのパーティションがAny()別の項目を呼び出すことができなくなります。

ただし、現在メソッド内でラムダ式を実行しAny()ているスレッドは、別のスレッドが成功したことを知る方法がないため、引き続き実行されます。新しいスレッドが を呼び出すのを防ぎAny()ますが、「非常に高価な」デリゲート内のすべてのスレッドをキャンセルするわけではありません。

余談ですが:

PLINQ は、LINQ to Objects とは異なり、実際には遅延実行を使用しません。を呼び出すAsParallel()と、IEnumerable<T>生成されたParallelQuery<T>が実際にルーチンの処理を並行して開始します。遅延実行は PLINQ の有効性を劇的に低下させます。これは、ワーク パーティショナーを作成して事前にスケジューリングしないと、並行してスケジュールを立てることができないためです。


編集:

これについて考えた後、ラムダが非常に高価な場合は、CancellationTokenの使用を検討することをお勧めします。PLINQ でのキャンセルのしくみについては、ブログで詳しく説明しています。通常、トークンを使用してThrowIfCancellationRequested()を呼び出すだけですが、 CancellationToken を使用してIsCancellationRequestedを確認することもできます。これにより、ラムダを「早期に終了」させ、バックグラウンド処理をより早く停止する方法を提供します。 ..

于 2010-03-08T19:00:04.123 に答える