Preservação da ordem em PLINQOrder Preservation in PLINQ

Em PLINQ, o objetivo é maximizar o desempenho mantendo a exatidão.In PLINQ, the goal is to maximize performance while maintaining correctness. Uma consulta deve ser executada o mais rápido possível, mas ainda produzir os resultados corretos.A query should run as fast as possible but still produce the correct results. Em alguns casos, a exatidão requer que a ordem da sequência de origem seja preservada. No entanto, a ordenação pode ser dispendiosa.In some cases, correctness requires the order of the source sequence to be preserved; however, ordering can be computationally expensive. Portanto, por padrão, o PLINQ não preserva a ordem da sequência de origem.Therefore, by default, PLINQ does not preserve the order of the source sequence. Nesse sentido, o PLINQ assemelha-se a LINQ to SQLLINQ to SQL, mas é diferente do LINQ to Objects que preserva a ordenação.In this regard, PLINQ resembles LINQ to SQLLINQ to SQL, but is unlike LINQ to Objects, which does preserve ordering.

Para substituir o comportamento padrão, ative a preservação da ordem usando o operador AsOrdered na sequência de origem.To override the default behavior, you can turn on order-preservation by using the AsOrdered operator on the source sequence. Posteriormente, você pode desativar a preservação da ordem na consulta usando o método AsUnordered.You can then turn off order preservation later in the query by using the AsUnordered method. Nos dois métodos, a consulta é processada com base na heurística que determina se a consulta deverá ser executada como paralela ou sequencial.With both methods, the query is processed based on the heuristics that determine whether to execute the query as parallel or as sequential. Para saber mais, veja Noções básicas sobre agilização em PLINQ.For more information, see Understanding Speedup in PLINQ.

O exemplo a seguir mostra uma consulta paralela não ordenada que filtra todos os elementos que correspondem a uma condição, sem tentar ordenar os resultados de qualquer forma.The following example shows an unordered parallel query that filters for all the elements that match a condition, without trying to order the results in any way.

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)

Essa consulta não necessariamente gera as primeiras 1.000 cidades que atendem à condição na sequência de origem, mas em vez disso, gera alguns conjuntos de 1.000 cidades que atendem à condição.This query does not necessarily produce the first 1000 cities in the source sequence that meet the condition, but rather some set of 1000 cities that meet the condition. Operadores de consulta PLINQ particionam a sequência de origem em várias subsequências que são processadas como tarefas simultâneas.PLINQ query operators partition the source sequence into multiple subsequences that are processed as concurrent tasks. Se a preservação da ordem não for especificada, os resultados de cada partição serão enviados para a próxima fase da consulta em uma ordem arbitrária.If order preservation is not specified, the results from each partition are handed off to the next stage of the query in an arbitrary order. Além disso, uma partição pode gerar um subconjunto de seus resultados antes de continuar a processar os elementos restantes.Also, a partition may yield a subset of its results before it continues to process the remaining elements. A ordem resultante pode ser sempre diferente.The resulting order may be different every time. O aplicativo não pode controlar isso porque depende da forma como o sistema operacional agenda os threads.Your application cannot control this because it depends on how the operating system schedules the threads.

O exemplo a seguir substitui o comportamento padrão usando o operador AsOrdered na sequência de origem.The following example overrides the default behavior by using the AsOrdered operator on the source sequence. Isso garante que o método Take retornará as primeiras 1.000 cidades na sequência de origem que atendam à condição.This ensures that the Take method returns the first 1000 cities in the source sequence that meet the condition.

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)

No entanto, essa consulta provavelmente não é executada tão rápido quanto a versão não ordenada já que ela deve controlar a ordenação original em toda as partições e, no tempo de mesclagem, verificar se a ordenação é consistente.However, this query probably does not run as fast as the unordered version because it must keep track of the original ordering throughout the partitions and at merge time ensure that the ordering is consistent. Portanto, é recomendável usar AsOrdered somente quando necessário e apenas para as partes da consulta que o exigem.Therefore, we recommend that you use AsOrdered only when it is required, and only for those parts of the query that require it. Quando a preservação da ordem já não for necessária, use AsUnordered para desativá-la.When order preservation is no longer required, use AsUnordered to turn it off. O exemplo a seguir realiza isso compondo duas consultas.The following example achieves this by composing two queries.

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) { /*...*/ }
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

Observe que o PLINQ preserva a ordenação de uma sequência produzida por operadores de imposição da ordem para o restante da consulta.Note that PLINQ preserves the ordering of a sequence produced by order-imposing operators for the rest of the query. Ou seja, operadores como OrderBy e ThenBy são tratados como se fossem seguidos por uma chamada para AsOrdered.In other words, operators such as OrderBy and ThenBy are treated as if they were followed by a call to AsOrdered.

Operadores de consulta e ordenaçãoQuery Operators and Ordering

Os operadores de consulta a seguir apresentam a preservação da ordem em todas as demais operações de uma consulta ou até que AsUnordered seja chamado:The following query operators introduce order preservation into all subsequent operations in a query, or until AsUnordered is called:

Os seguintes operadores de consulta PLINQ podem, em alguns casos, exigir sequências ordenadas de origem para produzir resultados corretos:The following PLINQ query operators may in some cases require ordered source sequences to produce correct results:

Alguns operadores de consulta PLINQ se comportam de forma diferente, dependendo se a sequência de origem for ordenada ou desordenada.Some PLINQ query operators behave differently, depending on whether their source sequence is ordered or unordered. A tabela a seguir lista esses operadores.The following table lists these operators.

OperadorOperator Resultado quando a sequência de origem é ordenadaResult when the source sequence is ordered Resultado quando a sequência de origem é desordenadaResult when the source sequence is unordered
Aggregate Saída não determinística para operações não associativas ou não comutativasNondeterministic output for nonassociative or noncommutative operations Saída não determinística para operações não associativas ou não comutativasNondeterministic output for nonassociative or noncommutative operations
All Não aplicávelNot applicable Não aplicávelNot applicable
Any Não aplicávelNot applicable Não aplicávelNot applicable
AsEnumerable Não aplicávelNot applicable Não aplicávelNot applicable
Average Saída não determinística para operações não associativas ou não comutativasNondeterministic output for nonassociative or noncommutative operations Saída não determinística para operações não associativas ou não comutativasNondeterministic output for nonassociative or noncommutative operations
Cast Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Concat Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Count Não aplicávelNot applicable Não aplicávelNot applicable
DefaultIfEmpty Não aplicávelNot applicable Não aplicávelNot applicable
Distinct Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
ElementAt Retorna o elemento especificadoReturn specified element Elemento arbitrárioArbitrary element
ElementAtOrDefault Retorna o elemento especificadoReturn specified element Elemento arbitrárioArbitrary element
Except Resultados não ordenadosUnordered results Resultados não ordenadosUnordered results
First Retorna o elemento especificadoReturn specified element Elemento arbitrárioArbitrary element
FirstOrDefault Retorna o elemento especificadoReturn specified element Elemento arbitrárioArbitrary element
ForAll Executa de forma não determinística em paraleloExecutes nondeterministically in parallel Executa de forma não determinística em paraleloExecutes nondeterministically in parallel
GroupBy Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
GroupJoin Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Intersect Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Join Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Last Retorna o elemento especificadoReturn specified element Elemento arbitrárioArbitrary element
LastOrDefault Retorna o elemento especificadoReturn specified element Elemento arbitrárioArbitrary element
LongCount Não aplicávelNot applicable Não aplicávelNot applicable
Min Não aplicávelNot applicable Não aplicávelNot applicable
OrderBy Reordena a sequênciaReorders the sequence Inicia nova seção ordenadaStarts new ordered section
OrderByDescending Reordena a sequênciaReorders the sequence Inicia nova seção ordenadaStarts new ordered section
Range Não aplicável (mesmo padrão de AsParallel)Not applicable (same default as AsParallel ) Não aplicávelNot applicable
Repeat Não aplicável (mesmo padrão de AsParallel)Not applicable (same default as AsParallel) Não aplicávelNot applicable
Reverse InverteReverses Não agirDoes nothing
Select Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Select (indexado)Select (indexed) Resultados ordenadosOrdered results Resultados não ordenados.Unordered results.
SelectMany Resultados ordenados.Ordered results. Resultados não ordenadosUnordered results
SelectMany (indexado)SelectMany (indexed) Resultados ordenados.Ordered results. Resultados não ordenados.Unordered results.
SequenceEqual Comparação ordenadaOrdered comparison Comparação não ordenadaUnordered comparison
Single Não aplicávelNot applicable Não aplicávelNot applicable
SingleOrDefault Não aplicávelNot applicable Não aplicávelNot applicable
Skip Ignora os primeiros n elementosSkips first n elements Ignora os n elementosSkips any n elements
SkipWhile Resultados ordenados.Ordered results. Não determinístico.Nondeterministic. Executa SkipWhile na ordem arbitrária atualPerforms SkipWhile on the current arbitrary order
Sum Saída não determinística para operações não associativas ou não comutativasNondeterministic output for nonassociative or noncommutative operations Saída não determinística para operações não associativas ou não comutativasNondeterministic output for nonassociative or noncommutative operations
Take Usa os primeiros n elementosTakes first n elements Usa quaisquer n elementosTakes any n elements
TakeWhile Resultados ordenadosOrdered results Não determinístico.Nondeterministic. Executa TakeWhile na ordem arbitrária atualPerforms TakeWhile on the current arbitrary order
ThenBy Suplementos OrderBySupplements OrderBy Suplementos OrderBySupplements OrderBy
ThenByDescending Suplementos OrderBySupplements OrderBy Suplementos OrderBySupplements OrderBy
ToArray Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
ToDictionary Não aplicávelNot applicable Não aplicávelNot applicable
ToList Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
ToLookup Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Union Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Where Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Where (indexado)Where (indexed) Resultados ordenadosOrdered results Resultados não ordenadosUnordered results
Zip Resultados ordenadosOrdered results Resultados não ordenadosUnordered results

Os resultados não ordenados não são ativamente embaralhados. Eles simplesmente não têm qualquer lógica de ordenação especial aplicada a eles.Unordered results are not actively shuffled; they simply do not have any special ordering logic applied to them. Em alguns casos, uma consulta não ordenada pode manter a ordenação da sequência de origem.In some cases, an unordered query may retain the ordering of the source sequence. No caso das consultas que usam o operador Select indexado, o PLINQ garante que os elementos de saída serão apresentados na ordem de índices crescentes, mas não garante quais índices serão atribuídos a quais elementos.For queries that use the indexed Select operator, PLINQ guarantees that the output elements will come out in the order of increasing indices, but makes no guarantees about which indices will be assigned to which elements.

Consulte tambémSee also