次の方法で共有


PLINQ での注文の保持

PLINQ では、正確性を維持しながらパフォーマンスを最大化することが目標です。 クエリはできるだけ速く実行する必要がありますが、正しい結果が生成されます。 場合によっては、ソース シーケンスの順序を保持する必要があります。ただし、順序付けは計算コストが高くなる可能性があります。 したがって、既定では、PLINQ はソース シーケンスの順序を保持しません。 この点で、PLINQ は LINQ to SQL に似ていますが、順序を保持する LINQ to Objects とは異なります。

既定の動作をオーバーライドするには、ソース シーケンスで AsOrdered 演算子を使用して、順序の保持を有効にします。 その後、 AsUnordered メソッドを使用して、クエリの後で注文の保持をオフにすることができます。 どちらの方法でも、クエリはヒューリスティックに基づいて処理され、クエリを並列または順次のいずれとして実行するかを決定します。 詳細については、「 PLINQ の高速化について」を参照してください。

次の例は、何らかの方法で結果を並べ替えることなく、条件に一致するすべての要素をフィルター処理する順序付けされていない並列クエリを示しています。

var cityQuery =
    (from city in cities.AsParallel()
     where city.Population > 10000
     select city).Take(1000);
Dim cityQuery = From city In cities.AsParallel()
                Where city.Population > 10000
                Take (1000)

このクエリでは、必ずしも条件を満たすソース シーケンスの最初の 1000 都市が生成されるのではなく、条件を満たす 1000 都市のセットが生成されます。 PLINQ クエリ演算子は、同時タスクとして処理される複数のサブシーケンスにソース シーケンスをパーティション分割します。 順序の保持が指定されていない場合、各パーティションの結果は任意の順序でクエリの次のステージに渡されます。 また、パーティションは、残りの要素の処理を続行する前に、結果のサブセットを生成する場合があります。 結果の順序は毎回異なる場合があります。 アプリケーションは、オペレーティング システムがスレッドをスケジュールする方法に依存するため、これを制御できません。

次の例では、ソース シーケンスで AsOrdered 演算子を使用して、既定の動作をオーバーライドします。 これにより、 Take メソッドは、条件を満たすソース シーケンス内の最初の 1000 都市を返します。

var orderedCities =
    (from city in cities.AsParallel().AsOrdered()
     where city.Population > 10000
     select city).Take(1000);

Dim orderedCities = From city In cities.AsParallel().AsOrdered()
                    Where city.Population > 10000
                    Take (1000)

ただし、このクエリは、パーティション全体の元の順序を追跡し、マージ時に順序が一貫していることを確認する必要があるため、順序付けされていないバージョンほど高速に実行されない可能性があります。 そのため、 AsOrdered は必要な場合にのみ使用し、必要なクエリの部分にのみ使用することをお勧めします。 注文の保存が不要になった場合は、 AsUnordered を使用してオフにします。 次の例では、2 つのクエリを作成することでこれを実現します。

var orderedCities2 =
    (from city in cities.AsParallel().AsOrdered()
     where city.Population > 10000
     select city).Take(1000);

var finalResult =
    from city in orderedCities2.AsUnordered()
    join p in people.AsParallel()
    on city.Name equals p.CityName into details
    from c in details
    select new
    {
        city.Name,
        Pop = city.Population,
        c.Mayor
    };

foreach (var city in finalResult) { /*...*/ }
Dim orderedCities2 = From city In cities.AsParallel().AsOrdered()
                     Where city.Population > 10000
                     Select city
                     Take (1000)

Dim finalResult = From city In orderedCities2.AsUnordered()
                  Join p In people.AsParallel() On city.Name Equals p.CityName
                  Select New With {.Name = city.Name, .Pop = city.Population, .Mayor = city.Mayor}

For Each city In finalResult
    Console.WriteLine(city.Name & ":" & city.Pop & ":" & city.Mayor)
Next

PLINQ は、クエリの残りの部分に対して順序付け演算子によって生成されるシーケンスの順序を保持することに注意してください。 つまり、 OrderByThenBy などの演算子は、 AsOrderedの呼び出しの後に続くかのように扱われます。

クエリ演算子と順序付け

次のクエリ演算子は、クエリ内の後続のすべての操作、または AsUnordered が呼び出されるまで、順序の保持を導入します。

次の PLINQ クエリ演算子では、正しい結果を生成するために順序付けされたソース シーケンスが必要な場合があります。

一部の PLINQ クエリ演算子の動作は、ソース シーケンスが順序付けされているか順序付けられていないかに応じて異なります。 次の表に、これらの演算子を示します。

オペレーター ソース シーケンスが並べ替えられた場合の結果 ソース シーケンスが順序付けされていない場合の結果
Aggregate 非関連付け操作または非コミット操作の非決定的出力 非関連付け操作または非コミット操作の非決定的出力
All 適用なし 適用なし
Any 適用なし 適用なし
AsEnumerable 適用なし 適用なし
Average 非関連付け操作または非コミット操作の非決定的出力 非関連付け操作または非コミット操作の非決定的出力
Cast 順序付けされた結果 順序付けされていない結果
Concat 順序付けされた結果 順序付けされていない結果
Count 適用なし 適用なし
DefaultIfEmpty 適用なし 適用なし
Distinct 順序付けされた結果 順序付けされていない結果
ElementAt 指定された要素を返します 任意の要素
ElementAtOrDefault 指定された要素を返します 任意の要素
Except 順序付けされていない結果 順序付けされていない結果
First 指定された要素を返します 任意の要素
FirstOrDefault 指定された要素を返します 任意の要素
ForAll 非決定的に並列で実行する 非決定的に並列で実行する
GroupBy 順序付けされた結果 順序付けされていない結果
GroupJoin 順序付けされた結果 順序付けされていない結果
Intersect 順序付けされた結果 順序付けされていない結果
Join 順序付けされた結果 順序付けされていない結果
Last 指定された要素を返します 任意の要素
LastOrDefault 指定された要素を返します 任意の要素
LongCount 適用なし 適用なし
Min 適用なし 適用なし
OrderBy シーケンスの順序を変更します。 新しい順序付けされたセクションを開始します
OrderByDescending シーケンスの順序を変更します。 新しい順序付けされたセクションを開始します
Range 適用できません ( AsParallel と同じ既定値) 適用なし
Repeat 適用できません ( AsParallelと同じ既定値) 適用なし
Reverse 反転 何もしない
Select 順序付けされた結果 順序付けされていない結果
Select (インデックス付き) 順序付けされた結果 順序付けされていない結果。
SelectMany 順序付けされた結果。 順序付けされていない結果
SelectMany (インデックス付き) 順序付けされた結果。 順序付けされていない結果。
SequenceEqual 順序付き比較 順序付けされていない比較
Single 適用なし 適用なし
SingleOrDefault 適用なし 適用なし
Skip 最初の n 個の要素 スキップします n 個の要素をスキップします
SkipWhile 順序付けされた結果。 非決定的。 現在の任意の順序で SkipWhile を実行します
Sum 非関連付け操作または非コミット操作の非決定的出力 非関連付け操作または非コミット操作の非決定的出力
Take 最初の n 要素を受け取ります 任意の n 要素を受け取ります
TakeWhile 順序付けされた結果 非決定的。 現在の任意の順序で TakeWhile を実行します
ThenBy サプリメント OrderBy サプリメント OrderBy
ThenByDescending サプリメント OrderBy サプリメント OrderBy
ToArray 順序付けされた結果 順序付けされていない結果
ToDictionary 適用なし 適用なし
ToList 順序付けされた結果 順序付けされていない結果
ToLookup 順序付けされた結果 順序付けされていない結果
Union 順序付けされた結果 順序付けされていない結果
Where 順序付けされた結果 順序付けされていない結果
Where (インデックス付き) 順序付けされた結果 順序付けされていない結果
Zip 順序付けされた結果 順序付けされていない結果

順序付けられていない結果はアクティブにシャッフルされません。特殊な順序付けロジックが適用されていないだけです。 場合によっては、順序付けされていないクエリでソース シーケンスの順序が保持される場合があります。 インデックス付き Select 演算子を使用するクエリの場合、PLINQ は、出力要素が増加するインデックスの順序で出力されることを保証しますが、どのインデックスがどの要素に割り当てられるかを保証しません。

こちらも参照ください