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 |
---|---|---|
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 |
|
Não aplicável. |
Não aplicável. |
|
Não aplicável. |
Não aplicável. |
|
Não aplicável. |
Não aplicável. |
|
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 |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Não aplicável. |
Não aplicável. |
|
Não aplicável. |
Não aplicável. |
|
Resultados ordenados |
Resultados não ordenados |
|
Retornar o elemento especificado |
Elemento arbitrário |
|
Retornar o elemento especificado |
Elemento arbitrário |
|
Resultados não ordenados |
Resultados não ordenados |
|
Retornar o elemento especificado |
Elemento arbitrário |
|
Retornar o elemento especificado |
Elemento arbitrário |
|
Nondeterministically executa em paralelo |
Nondeterministically executa em paralelo |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Retornar o elemento especificado |
Elemento arbitrário |
|
Retornar o elemento especificado |
Elemento arbitrário |
|
Não aplicável. |
Não aplicável. |
|
Não aplicável. |
Não aplicável. |
|
Reordena a seqüência. |
Inicia novas ordenadas da seção |
|
Reordena a seqüência. |
Inicia novas ordenadas da seção |
|
Não aplicável (mesmo padrão como AsParallel ) |
Não aplicável. |
|
Não aplicável (mesmo padrão como AsParallel) |
Não aplicável. |
|
Reverte |
Não faz nada |
|
Resultados ordenados |
Resultados não ordenados |
|
Select(indexados) |
Resultados ordenados |
Resultados não ordenados. |
Resultados ordenados. |
Resultados não ordenados |
|
SelectMany(indexados) |
Resultados ordenados. |
Resultados não ordenados. |
Comparação de ordenada |
Comparação não ordenada |
|
Não aplicável. |
Não aplicável. |
|
Não aplicável. |
Não aplicável. |
|
Ignora o primeiro n elementos |
Ignora qualquer n elementos |
|
Resultados ordenados. |
Não determinísticas. Executa SkipWhile na atual ordem arbitrária |
|
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 |
|
Leva primeiro n elementos |
Leva a qualquer n elementos |
|
Resultados ordenados |
Não determinísticas. Executa TakeWhile na atual ordem arbitrária |
|
SuplementosOrderBy |
SuplementosOrderBy |
|
SuplementosOrderBy |
SuplementosOrderBy |
|
Resultados ordenados |
Resultados não ordenados |
|
Não aplicável. |
Não aplicável. |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Resultados ordenados |
Resultados não ordenados |
|
Where(indexados) |
Resultados ordenados |
Resultados não ordenados |
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.