Dela via


Beställ bevarande i PLINQ

I PLINQ är målet att maximera prestandan samtidigt som korrektheten bibehålls. En fråga ska köras så snabbt som möjligt men ändå ge rätt resultat. I vissa fall kräver korrekthet att källsekvensens ordning bevaras. Beställningen kan dock vara beräkningsmässigt dyr. PLINQ bevarar därför som standard inte källsekvensens ordning. I det här avseendet liknar PLINQ LINQ till SQL, men är till skillnad från LINQ till Objekt, vilket bevarar ordningen.

Om du vill åsidosätta standardbeteendet kan du aktivera orderbevarande med hjälp av operatorn AsOrdered i källsekvensen. Du kan sedan inaktivera orderbevarande senare i frågan med hjälp AsUnordered av metoden . Med båda metoderna bearbetas frågan baserat på heuristiken som avgör om frågan ska köras som parallell eller sekventiell. Mer information finns i Förstå hastighet i PLINQ.

I följande exempel visas en oordnad parallell fråga som filtrerar för alla element som matchar ett villkor, utan att försöka sortera resultaten på något sätt.

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)

Den här frågan producerar inte nödvändigtvis de första 1 000 städerna i källsekvensen som uppfyller villkoret, utan snarare en uppsättning med 1 000 städer som uppfyller villkoret. PLINQ-frågeoperatorer partitionerar källsekvensen i flera underfrågor som bearbetas som samtidiga uppgifter. Om orderbevaring inte anges överlämnas resultatet från varje partition till nästa steg i frågan i godtycklig ordning. Dessutom kan en partition ge en delmängd av dess resultat innan den fortsätter att bearbeta de återstående elementen. Den resulterande ordningen kan vara olika varje gång. Programmet kan inte styra detta eftersom det beror på hur operativsystemet schemalägger trådarna.

I följande exempel åsidosätts standardbeteendet med hjälp av operatorn AsOrdered i källsekvensen. Detta säkerställer att Take metoden returnerar de första 1 000 städerna i källsekvensen som uppfyller villkoret.

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)

Den här frågan körs dock förmodligen inte lika snabbt som den osorterade versionen eftersom den måste hålla reda på den ursprungliga ordningen i partitionerna och vid sammanslagningstiden se till att ordningen är konsekvent. Därför rekommenderar vi att du endast använder AsOrdered när det krävs och endast för de delar av frågan som kräver det. När orderbevarande inte längre krävs kan du använda AsUnordered för att inaktivera det. I följande exempel uppnås detta genom att två frågor skapas.

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

Observera att PLINQ bevarar ordningen på en sekvens som genereras av order-imponerande operatorer för resten av frågan. Med andra ord behandlas operatorer som OrderBy och ThenBy som om de följdes av ett anrop till AsOrdered.

Frågeoperatorer och beställning

Följande frågeoperatorer introducerar orderbevarande i alla efterföljande åtgärder i en fråga eller tills anropas AsUnordered :

Följande PLINQ-frågeoperatorer kan i vissa fall kräva ordnade källsekvenser för att ge rätt resultat:

Vissa PLINQ-frågeoperatorer beter sig annorlunda, beroende på om deras källsekvens är ordnad eller osorterad. I följande tabell visas dessa operatorer.

Operator Resultat när källsekvensen sorteras Resultat när källsekvensen är oordnad
Aggregate Nondeterministiska utdata för icke-associerande eller icke-kommutativa åtgärder Nondeterministiska utdata för icke-associerande eller icke-kommutativa åtgärder
All Ej tillämpligt Saknas
Any Saknas Saknas
AsEnumerable Saknas Ej tillämpligt
Average Nondeterministiska utdata för icke-associerande eller icke-kommutativa åtgärder Nondeterministiska utdata för icke-associerande eller icke-kommutativa åtgärder
Cast Ordnade resultat Osorterade resultat
Concat Ordnade resultat Osorterade resultat
Count Ej tillämpligt Saknas
DefaultIfEmpty Saknas Ej tillämpligt
Distinct Ordnade resultat Osorterade resultat
ElementAt Returnera angivet element Godtyckligt element
ElementAtOrDefault Returnera angivet element Godtyckligt element
Except Osorterade resultat Osorterade resultat
First Returnera angivet element Godtyckligt element
FirstOrDefault Returnera angivet element Godtyckligt element
ForAll Kör icke-terministiskt parallellt Kör icke-terministiskt parallellt
GroupBy Ordnade resultat Osorterade resultat
GroupJoin Ordnade resultat Osorterade resultat
Intersect Ordnade resultat Osorterade resultat
Join Ordnade resultat Osorterade resultat
Last Returnera angivet element Godtyckligt element
LastOrDefault Returnera angivet element Godtyckligt element
LongCount Ej tillämpligt Saknas
Min Saknas Ej tillämpligt
OrderBy Ändrar ordning på sekvensen Startar nytt ordnat avsnitt
OrderByDescending Ändrar ordning på sekvensen Startar nytt ordnat avsnitt
Range Inte tillämpligt (samma standard som AsParallel ) Inte tillämpligt
Repeat Inte tillämpligt (samma standard som AsParallel) Inte tillämpligt
Reverse Vänder Gör ingenting
Select Ordnade resultat Osorterade resultat
Select (indexerat) Ordnade resultat Osorterade resultat.
SelectMany Ordnade resultat. Osorterade resultat
SelectMany (indexerat) Ordnade resultat. Osorterade resultat.
SequenceEqual Ordnad jämförelse Osorterad jämförelse
Single Ej tillämpligt Saknas
SingleOrDefault Saknas Ej tillämpligt
Skip Hoppar över de första n elementen Hoppar över alla n element
SkipWhile Ordnade resultat. Nondeterministisk. Utför SkipWhile på den aktuella godtyckliga ordningen
Sum Nondeterministiska utdata för icke-associerande eller icke-kommutativa åtgärder Nondeterministiska utdata för icke-associerande eller icke-kommutativa åtgärder
Take Tar de första n elementen Tar alla n element
TakeWhile Ordnade resultat Nondeterministisk. Utför TakeWhile på den aktuella godtyckliga ordningen
ThenBy Tillägg OrderBy Tillägg OrderBy
ThenByDescending Tillägg OrderBy Tillägg OrderBy
ToArray Ordnade resultat Osorterade resultat
ToDictionary Ej tillämpligt Ej tillämpligt
ToList Ordnade resultat Osorterade resultat
ToLookup Ordnade resultat Osorterade resultat
Union Ordnade resultat Osorterade resultat
Where Ordnade resultat Osorterade resultat
Where (indexerat) Ordnade resultat Osorterade resultat
Zip Ordnade resultat Osorterade resultat

Osorterade resultat blandas inte aktivt. De har helt enkelt inte någon särskild ordningslogik som tillämpas på dem. I vissa fall kan en osorterad fråga behålla ordningen på källsekvensen. För frågor som använder den indexerade Select-operatorn garanterar PLINQ att utdataelementen kommer ut i ordningen för att öka indexen, men ger inga garantier om vilka index som ska tilldelas till vilka element.

Se även