Sdílet prostřednictvím


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

Aggregate

Nedeterministický výstup pro neasociativní či nekomutativní operace

Nedeterministický výstup pro neasociativní či nekomutativní operace

All<TSource>

Nelze použít

Nelze použít

Any

Nelze použít

Nelze použít

AsEnumerable<TSource>

Nelze použít

Nelze použít

Average

Nedeterministický výstup pro neasociativní či nekomutativní operace

Nedeterministický výstup pro neasociativní či nekomutativní operace

Cast<TResult>

Uspořádané výsledky

Neuspořádané výsledky

Concat

Uspořádané výsledky

Neuspořádané výsledky

Count

Nelze použít

Nelze použít

DefaultIfEmpty

Nelze použít

Nelze použít

Distinct

Uspořádané výsledky

Neuspořádané výsledky

ElementAt<TSource>

Vrací požadovaný prvek

Libovolný prvek

ElementAtOrDefault<TSource>

Vrací požadovaný prvek

Libovolný prvek

Except

Neuspořádané výsledky

Neuspořádané výsledky

First

Vrací požadovaný prvek

Libovolný prvek

FirstOrDefault

Vrací požadovaný prvek

Libovolný prvek

ForAll<TSource>

Paralelně se zpracuje nedeterministicky

Paralelně se zpracuje nedeterministicky

GroupBy

Uspořádané výsledky

Neuspořádané výsledky

GroupJoin

Uspořádané výsledky

Neuspořádané výsledky

Intersect

Uspořádané výsledky

Neuspořádané výsledky

Join

Uspořádané výsledky

Neuspořádané výsledky

Last

Vrací požadovaný prvek

Libovolný prvek

LastOrDefault

Vrací požadovaný prvek

Libovolný prvek

LongCount

Nelze použít

Nelze použít

Min

Nelze použít

Nelze použít

OrderBy

Znovu uspořádá sekvenci

Začne novou uspořádanou sekci

OrderByDescending

Znovu uspořádá sekvenci

Začne novou uspořádanou sekci

Range

Není použitelné (stejné jako výchozí AsParallel )

Nelze použít

Repeat<TResult>

Nelze použít (stejné výchozí chování jako s AsParallel)

Nelze použít

Reverse<TSource>

Obrátí pořadí

Neprovede žádnou akci

Select

Uspořádané výsledky

Neuspořádané výsledky

Select(index)

Uspořádané výsledky

Neuspořádané výsledky.

SelectMany

Uspořádané výsledky.

Neuspořádané výsledky

SelectMany(index)

Uspořádané výsledky.

Neuspořádané výsledky.

SequenceEqual

Uspořádané porovnání

Neuspořádané porovnání

Single

Nelze použít

Nelze použít

SingleOrDefault

Nelze použít

Nelze použít

Skip<TSource>

Přeskočí prvních n prvků

Přeskočí libovolných n prvků

SkipWhile

Uspořádané výsledky.

Nedeterministické. Provádí SkipWhile na libovolné aktuální pořadí

Sum

Nedeterministický výstup pro neasociativní či nekomutativní operace

Nedeterministický výstup pro neasociativní či nekomutativní operace

Take<TSource>

Získá prvních n prvků

Získá n libovolných prvků

TakeWhile

Uspořádané výsledky

Nedeterministické. Provádí TakeWhile na libovolné aktuální pořadí

ThenBy

Doplňuje OrderBy

Doplňuje OrderBy

ThenByDescending

Doplňuje OrderBy

Doplňuje OrderBy

ToArray<TSource>

Uspořádané výsledky

Neuspořádané výsledky

ToDictionary

Nelze použít

Nelze použít

ToList<TSource>

Uspořádané výsledky

Neuspořádané výsledky

ToLookup

Uspořádané výsledky

Neuspořádané výsledky

Union

Uspořádané výsledky

Neuspořádané výsledky

Where

Uspořádané výsledky

Neuspořádané výsledky

Where(index)

Uspořádané výsledky

Neuspořádané výsledky

Zip

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é.

Viz také

Koncepty

Paralelní LINQ (PLINQ)

Paralelní programování v rozhraní .NET Framework