Delen via


Behoud van volgorde in PLINQ

In PLINQ is het doel om de prestaties te maximaliseren terwijl de juistheid behouden blijft. Een query moet zo snel mogelijk worden uitgevoerd, maar toch de juiste resultaten opleveren. In sommige gevallen moet de volgorde van de bronvolgorde behouden blijven; bestellen kan echter rekenkundig duur zijn. Daarom behoudt PLINQ standaard niet de volgorde van de bronvolgorde. In dit opzicht lijkt PLINQ op LINQ naar SQL, maar is in tegenstelling tot LINQ naar objecten, die de volgorde wel behouden.

Als u het standaardgedrag wilt overschrijven, kunt u orderbehoud inschakelen met behulp van de AsOrdered operator in de bronvolgorde. U kunt het behoud van bestellingen later in de query uitschakelen met behulp van de AsUnordered methode. Bij beide methoden wordt de query verwerkt op basis van de heuristiek die bepaalt of de query parallel of als sequentiële query moet worden uitgevoerd. Zie Inzicht in snelheid in PLINQ voor meer informatie.

In het volgende voorbeeld ziet u een niet-geordende parallelle query die filtert op alle elementen die overeenkomen met een voorwaarde, zonder de resultaten op welke manier dan ook te ordenen.

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)

Deze query produceert niet noodzakelijkerwijs de eerste 1000 steden in de bronreeks die voldoen aan de voorwaarde, maar in plaats daarvan een aantal van 1000 steden die voldoen aan de voorwaarde. PLINQ-queryoperators partitioneren de bronvolgorde in meerdere subsequences die als gelijktijdige taken worden verwerkt. Als het behoud van de volgorde niet is opgegeven, worden de resultaten van elke partitie in een willekeurige volgorde overgedragen aan de volgende fase van de query. Een partitie kan ook een subset van de resultaten opleveren voordat deze de resterende elementen blijft verwerken. De resulterende volgorde kan elke keer anders zijn. Uw toepassing kan dit niet beheren omdat dit afhankelijk is van de wijze waarop het besturingssysteem de threads plant.

In het volgende voorbeeld wordt het standaardgedrag overschreven met behulp van de AsOrdered operator in de bronreeks. Dit zorgt ervoor dat de Take methode de eerste 1000 steden in de bronreeks retourneert die voldoen aan de voorwaarde.

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)

Deze query wordt echter waarschijnlijk niet zo snel uitgevoerd als de niet-geordende versie, omdat deze de oorspronkelijke volgorde in de partities moet bijhouden en tegelijkertijd ervoor moet zorgen dat de volgorde consistent is. Daarom raden we u aan alleen te gebruiken AsOrdered wanneer dit vereist is en alleen voor die onderdelen van de query waarvoor deze is vereist. Als het bewaren van bestellingen niet meer nodig is, kunt u deze AsUnordered uitschakelen. In het volgende voorbeeld wordt dit bereikt door twee query's op te stellen.

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

Houd er rekening mee dat PLINQ de volgorde behoudt van een reeks die wordt geproduceerd door order-imponerende operators voor de rest van de query. Met andere woorden, operators zoals OrderBy en ThenBy worden behandeld alsof ze worden gevolgd door een aanroep naar AsOrdered.

Queryoperators en volgorde

De volgende queryoperators zorgen voor orderbehoud in alle volgende bewerkingen in een query of totdat AsUnordered deze wordt aangeroepen:

De volgende PLINQ-queryoperators kunnen in sommige gevallen geordende bronreeksen vereisen om de juiste resultaten te produceren:

Sommige PLINQ-queryoperators gedragen zich anders, afhankelijk van of de bronvolgorde is gerangschikt of niet. De volgende tabel bevat deze operators.

Operator Resultaat wanneer de bronvolgorde is geordend Resultaat wanneer de bronvolgorde niet is gerangschikt
Aggregate Niet-deterministische uitvoer voor niet-gekoppelde of niet-commutatieve bewerkingen Niet-deterministische uitvoer voor niet-gekoppelde of niet-commutatieve bewerkingen
All Niet van toepassing Niet van toepassing
Any Niet van toepassing Niet van toepassing
AsEnumerable Niet van toepassing Niet van toepassing
Average Niet-deterministische uitvoer voor niet-gekoppelde of niet-commutatieve bewerkingen Niet-deterministische uitvoer voor niet-gekoppelde of niet-commutatieve bewerkingen
Cast Geordende resultaten Niet-geordende resultaten
Concat Geordende resultaten Niet-geordende resultaten
Count Niet van toepassing Niet van toepassing
DefaultIfEmpty Niet van toepassing Niet van toepassing
Distinct Geordende resultaten Niet-geordende resultaten
ElementAt Opgegeven element retourneren Willekeurig element
ElementAtOrDefault Opgegeven element retourneren Willekeurig element
Except Niet-geordende resultaten Niet-geordende resultaten
First Opgegeven element retourneren Willekeurig element
FirstOrDefault Opgegeven element retourneren Willekeurig element
ForAll Voert niet-deterministisch parallel uit Voert niet-deterministisch parallel uit
GroupBy Geordende resultaten Niet-geordende resultaten
GroupJoin Geordende resultaten Niet-geordende resultaten
Intersect Geordende resultaten Niet-geordende resultaten
Join Geordende resultaten Niet-geordende resultaten
Last Opgegeven element retourneren Willekeurig element
LastOrDefault Opgegeven element retourneren Willekeurig element
LongCount Niet van toepassing Niet van toepassing
Min Niet van toepassing Niet van toepassing
OrderBy De volgorde van de volgorde wijzigen Nieuwe geordende sectie starten
OrderByDescending De volgorde van de volgorde wijzigen Nieuwe geordende sectie starten
Range Niet van toepassing (dezelfde standaardwaarde als AsParallel ) Niet van toepassing
Repeat Niet van toepassing (dezelfde standaardwaarde als AsParallel) Niet van toepassing
Reverse Keert Doet niets
Select Geordende resultaten Niet-geordende resultaten
Select (geïndexeerd) Geordende resultaten Niet-geordende resultaten.
SelectMany Geordende resultaten. Niet-geordende resultaten
SelectMany (geïndexeerd) Geordende resultaten. Niet-geordende resultaten.
SequenceEqual Geordende vergelijking Niet-geordende vergelijking
Single Niet van toepassing Niet van toepassing
SingleOrDefault Niet van toepassing Niet van toepassing
Skip Eerste n elementen overslaan Slaat alle n elementen over
SkipWhile Geordende resultaten. Deterministische. Voert SkipWhile uit op de huidige willekeurige volgorde
Sum Niet-deterministische uitvoer voor niet-gekoppelde of niet-commutatieve bewerkingen Niet-deterministische uitvoer voor niet-gekoppelde of niet-commutatieve bewerkingen
Take Neemt eerste n elementen Neemt alle n elementen
TakeWhile Geordende resultaten Deterministische. Voert TakeWhile uit op de huidige willekeurige volgorde
ThenBy Supplementen OrderBy Supplementen OrderBy
ThenByDescending Supplementen OrderBy Supplementen OrderBy
ToArray Geordende resultaten Niet-geordende resultaten
ToDictionary Niet van toepassing Niet van toepassing
ToList Geordende resultaten Niet-geordende resultaten
ToLookup Geordende resultaten Niet-geordende resultaten
Union Geordende resultaten Niet-geordende resultaten
Where Geordende resultaten Niet-geordende resultaten
Where (geïndexeerd) Geordende resultaten Niet-geordende resultaten
Zip Geordende resultaten Niet-geordende resultaten

Ongeorderdende resultaten worden niet actief in willekeurige volgorde gebracht; ze hebben gewoon geen speciale volgordelogica toegepast. In sommige gevallen kan een niet-geordende query de volgorde van de bronvolgorde behouden. Voor query's die gebruikmaken van de geïndexeerde select-operator, garandeert PLINQ dat de uitvoerelementen worden weergegeven in de volgorde van toenemende indexen, maar geen garanties geeft over welke indexen aan welke elementen worden toegewezen.

Zie ook