Zachování pořadí v PLINQ
V PLINQ je cílem maximalizace výkonu při zachování korektnosti. Dotaz by měl běžet co nejrychleji, ale stále produkovat správné výsledky. V některých případech je pro správnost vyžadováno zachování pořadí zdrojové sekvence dat; ovšem, řazení může být výpočetně náročné. Proto ve výchozím nastavení PLINQ nezachová pořadí zdrojové sekvence dat. V tomto ohledu se PLINQ podobá LINQ to SQL, ale ne jako LINQ to Objects, kde je pořadí zachováváno.
Chcete-li změnit výchozí chování, můžete zapnout zachování pořadí použitím operátoru AsOrdered na zdrojovou sekvenci dat. Zachování pořadí lze později v dotaze vypnout pomocí metody AsUnordered<TSource>. Obě metody zpracování dotazu se na základě heuristické metody, které určují, zda spustit dotaz jako paralelní nebo jako sekvenční. Další informace naleznete v tématu Principy Vančurovou v PLINQ.
Následující příklad ukazuje neuspořádaný paralelní dotaz, který filtruje všechny prvky, které vyhovují podmínce, bez pokusu jakýmkoliv způsobem řadit výsledky.
Dim cityQuery = From city In cities.AsParallel()
Where City.Population > 10000
Take (1000)
var cityQuery = (from city in cities.AsParallel()
where city.Population > 10000
select city)
.Take(1000);
Tento dotaz nevrátí nutně prvních 1000 měst v zdrojové sekvenci dat, které splňují podmínku, ale spíše libovolnou množinu 1000 měst, které podmínku splňují. Operátory PLINQ dotazů rozdělují zdrojovou sekvenci dat do více dílčích sekvencí, které jsou zpracovány jako souběžné úlohy. Pokud není vyžádáno zachování pořadí, jsou výsledky z každé dílčí sekvence předány do další fáze dotazu v libovolném pořadí. Dílčí sekvence také může předat podmnožinu svých výsledků před tím, než pokračuje ve zpracování zbývajících prvků. Výsledné pořadí může být pokaždé jiné. Aplikace toto nemůže ovlivnit, protože pořadí závisí na způsobu, jakým operační systém naplánuje běh vláken.
Následující příklad přepisuje výchozí chování použitím operátoru AsOrdered na zdrojovou sekvenci dat. Tím zajistíte, že Take<TSource> Metoda vrátí prvních deset měst v posloupnosti zdroj splňující podmínku.
Dim orderedCities = From city In cities.AsParallel().AsOrdered()
Where City.Population > 10000
Take (1000)
var orderedCities = (from city in cities.AsParallel().AsOrdered()
where city.Population > 10000
select city)
.Take(1000);
Tento dotaz však pravděpodobně nepoběží stejně rychle jako neuspořádaná verze, protože dotaz si musí udržovat přehled o původním pořadí skrz dílčí sekvence a musí v okamžiku sloučení zajistit, aby bylo pořadí konzistentní. Proto je doporučeno používat AsOrdered pouze v případě, že je to nutné a pouze pro ty části dotazů, které to vyžadují. Ve chvíli kdy již není zachování pořadí požadováno, použijte AsUnordered<TSource> abyste jej vypnuli. Následující příklad tohoto dosahuje vytvořením dvou dotazů.
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
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 { Name = city.Name, Pop = city.Population, Mayor = c.Mayor };
foreach (var city in finalResult) { /*...*/ }
Poznámka: PLINQ v celé zbývající části dotazu zachová pořadí sekvence vyprodukované pomocí operátorů vnucujících řazení. Jinými slovy, operátory, jako například OrderBy nebo ThenBy, jsou zpracovány jako by byly následovány voláním AsOrdered.
Operátory dotazů a řazení
Následující operátory dotazu zavádí zachování pořadí do všech následných operací v dotazu (pokud není zavolána metoda AsUnordered<TSource>):
Následující operátory PLINQ dotazu mohou v některých případech pro správnost výsledku vyžadovat uspořádanou zdrojovou sekvenci dat:
Některé operátory PLINQ dotazu se chovají odlišně, v závislosti na tom, zda je jejich zdrojová sekvence dat uspořádaná nebo ne. V následující tabulce je uveden seznam těchto operátorů.
Operátor |
Výsledek při uspořádané zdrojové sekvenci dat |
Výsledek při neuspořádané zdrojové sekvenci dat |
---|---|---|
Nedeterministický výstup pro neasociativní či nekomutativní operace |
Nedeterministický výstup pro neasociativní či nekomutativní operace |
|
Nelze použít |
Nelze použít |
|
Nelze použít |
Nelze použít |
|
Nelze použít |
Nelze použít |
|
Nedeterministický výstup pro neasociativní či nekomutativní operace |
Nedeterministický výstup pro neasociativní či nekomutativní operace |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Nelze použít |
Nelze použít |
|
Nelze použít |
Nelze použít |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Vrací požadovaný prvek |
Libovolný prvek |
|
Vrací požadovaný prvek |
Libovolný prvek |
|
Neuspořádané výsledky |
Neuspořádané výsledky |
|
Vrací požadovaný prvek |
Libovolný prvek |
|
Vrací požadovaný prvek |
Libovolný prvek |
|
Paralelně se zpracuje nedeterministicky |
Paralelně se zpracuje nedeterministicky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Vrací požadovaný prvek |
Libovolný prvek |
|
Vrací požadovaný prvek |
Libovolný prvek |
|
Nelze použít |
Nelze použít |
|
Nelze použít |
Nelze použít |
|
Znovu uspořádá sekvenci |
Začne novou uspořádanou sekci |
|
Znovu uspořádá sekvenci |
Začne novou uspořádanou sekci |
|
Není použitelné (stejné jako výchozí AsParallel ) |
Nelze použít |
|
Nelze použít (stejné výchozí chování jako s AsParallel) |
Nelze použít |
|
Obrátí pořadí |
Neprovede žádnou akci |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Select(index) |
Uspořádané výsledky |
Neuspořádané výsledky. |
Uspořádané výsledky. |
Neuspořádané výsledky |
|
SelectMany(index) |
Uspořádané výsledky. |
Neuspořádané výsledky. |
Uspořádané porovnání |
Neuspořádané porovnání |
|
Nelze použít |
Nelze použít |
|
Nelze použít |
Nelze použít |
|
Přeskočí prvních n prvků |
Přeskočí libovolných n prvků |
|
Uspořádané výsledky. |
Nedeterministické. Provádí SkipWhile na libovolné aktuální pořadí |
|
Nedeterministický výstup pro neasociativní či nekomutativní operace |
Nedeterministický výstup pro neasociativní či nekomutativní operace |
|
Získá prvních n prvků |
Získá n libovolných prvků |
|
Uspořádané výsledky |
Nedeterministické. Provádí TakeWhile na libovolné aktuální pořadí |
|
Doplňuje OrderBy |
Doplňuje OrderBy |
|
Doplňuje OrderBy |
Doplňuje OrderBy |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Nelze použít |
Nelze použít |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Uspořádané výsledky |
Neuspořádané výsledky |
|
Where(index) |
Uspořádané výsledky |
Neuspořádané výsledky |
Uspořádané výsledky |
Neuspořádané výsledky |
Neuspořádané výsledky jsou aktivně nepřehází; jednoduše nemají žádné zvláštní logiku řazení použito. V některých případech může zachovat neuspořádané dotazu řazení pořadí zdroje. Pro dotazy, které indexované vybrat operátor záruky PLINQ, bude výstup prvky přijdete v pořadí podle vzrůstající indexy, ale neposkytuje žádné záruky, o které indexy budou přiřazeny prvky, které.