Compartilhar via


Preservação da ordem PLINQ

PLINQ, o objetivo é maximizar o desempenho, mantendo a correção. Uma consulta deve executar mais rápido possível, mas ainda produzir os resultados corretos. Em alguns casos, a correção exige a ordem da seqüência de origem seja preservado; No entanto, o pedido pode ser dispendioso. Portanto, por padrão, o PLINQ não preserva a ordem da seqüência de origem. Em relação a isso, o PLINQ semelhante LINQ to SQL, mas é diferente de LINQ to Objects, que preservam a ordenação.

Para substituir o comportamento padrão, você pode ativar preservação da ordem, usando o AsOrdered o operador na seqüência de origem. Você pode ativar desativar a preservação da ordem mais tarde na consulta usando o AsUnordered<TSource> método. Com ambos os métodos, a consulta é processada com base em heurística de determinar se deseja executar a consulta como paralelo ou seqüenciais. Para obter mais informações, consulte Aumento de velocidade de compreensão no PLINQ.

O exemplo a seguir mostra uma consulta paralela desordenada que filtra para todos os elementos que correspondam a uma condição, sem tentar a ordem dos resultados de qualquer maneira.

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);

Esta consulta não necessariamente produz as primeiros 1000 cidades na seqüência de origem que satisfazem a condição, mas em vez disso, um conjunto de cidades de 1000 que satisfazem a condição. Os operadores de consulta PLINQ particionam a seqüência de origem em várias subseqüências que são processadas como tarefas simultâneas. Se a preservação da ordem não for especificada, os resultados de cada partição serão passados para o próximo estágio da consulta em uma ordem arbitrária. Além disso, uma partição pode produzir um subconjunto de seus resultados antes de continuar a processar os elementos restantes. A ordem resultante pode ser diferente cada vez. Seu aplicativo não é possível controlar isso porque depende do modo como o sistema operacional agenda os threads.

O exemplo a seguir substitui o comportamento padrão usando o AsOrdered o operador na seqüência de origem. Isso garante que o Take<TSource> método retorna as 10 primeiras cidades na seqüência de origem que atendem a condição.

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);

No entanto, essa consulta provavelmente não é executado tão rapidamente quanto a versão desordenada porque ele deve controlar a ordem original em toda as partições e ao tempo de mesclagem, garantir a ordenação é consistente. Portanto, recomendamos que você use AsOrdered somente quando necessário e somente para essas partes da consulta que exigem que o proprietário. Quando a preservação da ordem não é mais necessária, use AsUnordered<TSource> para ativá-lo desativado. O exemplo a seguir realiza isso pela composição de duas consultas.

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

Observe que o PLINQ preserva a ordem de uma seqüência produzida pelos operadores de imposição de ordem para o resto da consulta. Em outras palavras, os operadores, como OrderBy e ThenBy são tratados como se eles foram seguidos por uma chamada para AsOrdered.

Operadores de consulta e pedidos

Os seguintes operadores de consulta introduzem a preservação da ordem em operações subseqüentes em uma consulta, ou até AsUnordered<TSource> é chamado:

Em alguns casos, os seguintes operadores de consulta PLINQ podem exigir seqüências ordenada de origem para produzir resultados corretos:

Alguns operadores de consulta PLINQ se comportam de forma diferente, dependendo de sua seqüência de origem é ordenada ou não ordenada. A tabela a seguir lista esses operadores.

Operador

Resultado quando a seqüência de origem é ordenada.

Quando a seqüência de origem é desordenada de resultado

Aggregate

Saída não determinística para operações de nonassociative ou noncommutative

Saída não determinística para operações de nonassociative ou noncommutative

All<TSource>

Não aplicável.

Não aplicável.

Any

Não aplicável.

Não aplicável.

AsEnumerable<TSource>

Não aplicável.

Não aplicável.

Average

Saída não determinística para operações de nonassociative ou noncommutative

Saída não determinística para operações de nonassociative ou noncommutative

Cast<TResult>

Resultados ordenados

Resultados não ordenados

Concat

Resultados ordenados

Resultados não ordenados

Count

Não aplicável.

Não aplicável.

DefaultIfEmpty

Não aplicável.

Não aplicável.

Distinct

Resultados ordenados

Resultados não ordenados

ElementAt<TSource>

Retornar o elemento especificado

Elemento arbitrário

ElementAtOrDefault<TSource>

Retornar o elemento especificado

Elemento arbitrário

Except

Resultados não ordenados

Resultados não ordenados

First

Retornar o elemento especificado

Elemento arbitrário

FirstOrDefault

Retornar o elemento especificado

Elemento arbitrário

ForAll<TSource>

Nondeterministically executa em paralelo

Nondeterministically executa em paralelo

GroupBy

Resultados ordenados

Resultados não ordenados

GroupJoin

Resultados ordenados

Resultados não ordenados

Intersect

Resultados ordenados

Resultados não ordenados

Join

Resultados ordenados

Resultados não ordenados

Last

Retornar o elemento especificado

Elemento arbitrário

LastOrDefault

Retornar o elemento especificado

Elemento arbitrário

LongCount

Não aplicável.

Não aplicável.

Min

Não aplicável.

Não aplicável.

OrderBy

Reordena a seqüência.

Inicia novas ordenadas da seção

OrderByDescending

Reordena a seqüência.

Inicia novas ordenadas da seção

Range

Não aplicável (mesmo padrão como AsParallel )

Não aplicável.

Repeat<TResult>

Não aplicável (mesmo padrão como AsParallel)

Não aplicável.

Reverse<TSource>

Reverte

Não faz nada

Select

Resultados ordenados

Resultados não ordenados

Select(indexados)

Resultados ordenados

Resultados não ordenados.

SelectMany

Resultados ordenados.

Resultados não ordenados

SelectMany(indexados)

Resultados ordenados.

Resultados não ordenados.

SequenceEqual

Comparação de ordenada

Comparação não ordenada

Single

Não aplicável.

Não aplicável.

SingleOrDefault

Não aplicável.

Não aplicável.

Skip<TSource>

Ignora o primeiro n elementos

Ignora qualquer n elementos

SkipWhile

Resultados ordenados.

Não determinísticas. Executa SkipWhile na atual ordem arbitrária

Sum

Saída não determinística para operações de nonassociative ou noncommutative

Saída não determinística para operações de nonassociative ou noncommutative

Take<TSource>

Leva primeiro n elementos

Leva a qualquer n elementos

TakeWhile

Resultados ordenados

Não determinísticas. Executa TakeWhile na atual ordem arbitrária

ThenBy

SuplementosOrderBy

SuplementosOrderBy

ThenByDescending

SuplementosOrderBy

SuplementosOrderBy

ToTSource>

Resultados ordenados

Resultados não ordenados

ToDictionary

Não aplicável.

Não aplicável.

ToList<TSource>

Resultados ordenados

Resultados não ordenados

ToLookup

Resultados ordenados

Resultados não ordenados

Union

Resultados ordenados

Resultados não ordenados

Where

Resultados ordenados

Resultados não ordenados

Where(indexados)

Resultados ordenados

Resultados não ordenados

Zip

Resultados ordenados

Resultados não ordenados

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. Em alguns casos, uma consulta de não ordenada pode reter a ordenação da seqüência de origem. Para consultas que usam o operador Select indexado, PLINQ garante que os elementos de saída vai sair na ordem de cada vez maiores índices, mas faz sem garantias sobre quais índices serão atribuídas aos quais elementos.

Consulte também

Conceitos

Parallel LINQ PLINQ)

Programação em paralela a.NET Framework