他の人が正しく答えているように、ForAll
メソッドは特定の順序で列挙可能な要素に対してアクションを実行することが保証されることはなく、AsOrdered()
メソッド呼び出しを黙って無視します。
元の順序にできるだけ近い方法で列挙可能な要素に対してアクションを実行する正当な理由がある読者の利益のために(並列処理のコンテキストで合理的である限り)、以下の拡張メソッドが役立つ場合があります。
public static void ForAllInApproximateOrder<TSource>(this ParallelQuery<TSource> source, Action<TSource> action) {
Partitioner.Create( source )
.AsParallel()
.AsOrdered()
.ForAll( e => action( e ) );
}
これは、次のように使用できます。
orderedElements.AsParallel()
.ForAllInApproximateOrder( e => DoSomething( e ) );
上記の拡張メソッドはPLINQForAll
を使用するのではなくParallel.ForEach
、PLINQによって内部的に使用されるスレッドモデルを継承することに注意してください(これはParallel.ForEach
、私の経験ではデフォルトではそれほど積極的ではありません)。を使用した同様の拡張方法をParallel.ForEach
以下に示します。
public static void ForEachInApproximateOrder<TSource>(this ParallelQuery<TSource> source, Action<TSource> action) {
source = Partitioner.Create( source )
.AsParallel()
.AsOrdered();
Parallel.ForEach( source , e => action( e ) );
}
これは、次のように使用できます。
orderedElements.AsParallel()
.ForEachInApproximateOrder( e => DoSomething( e ) );
上記の拡張メソッドのいずれかを使用する場合、クエリにチェーンAsOrdered()
する必要はありません。とにかく内部的に呼び出されます。
私はこれらの方法が粗い粒子の重要性を持つ要素を処理するのに役立つことを発見しました。たとえば、最も古いものから始めて、最も新しいものに向かって作業するレコードを処理すると便利な場合があります。多くの場合、レコードの正確な順序は必要ありません。通常、古いレコードが新しいレコードの前に処理される限りです。同様に、優先度が低い/中程度/高いレコードは、ほとんどの場合、優先度の高いレコードが優先度の低いレコードの前に処理されるように処理できますが、エッジケースはそれほど遅れていません。