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.