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 は、クエリの残りの部分に対して順序付け演算子によって生成されるシーケンスの順序を保持することに注意してください。 つまり、 OrderBy や ThenBy などの演算子は、 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 は、出力要素が増加するインデックスの順序で出力されることを保証しますが、どのインデックスがどの要素に割り当てられるかを保証しません。
こちらも参照ください
.NET