Opções de mesclagem em PLINQ

Quando uma consulta está sendo executada como paralela, o PLINQ faz a partição da sequência de origem para que várias threads possam funcionar em diferentes partes simultaneamente, normalmente em threads separados. Se os resultados forem consumidos em um thread, por exemplo, em um loop foreach (For Each em Visual Basic), os resultados de cada thread precisarão ser mesclados novamente em uma sequência. O tipo de mesclagem executado pelo PLINQ depende dos operadores que estão presentes na consulta. Por exemplo, os operadores que impõem uma nova ordem aos resultados devem armazenar em buffer todos os elementos em todos os threads. Do ponto de vista do thread de consumo (que também é o thread do usuário do aplicativo), uma consulta totalmente armazenada em buffer pode ser executada por um período significativo de tempo antes de produzir seu primeiro resultado. Por padrão, outros operadores são parcialmente armazenados em buffer e geram seus resultados em lotes. Um operador ForAll não é armazenado em buffer por padrão. Ele gera todos os elementos de todos os threads imediatamente.

Usando o método WithMergeOptions, conforme mostrado no exemplo a seguir, você pode fornecer uma dica ao PLINQ indicando o tipo de mesclagem que deverá ser executada.

var scanLines = from n in nums.AsParallel()
                    .WithMergeOptions(ParallelMergeOptions.NotBuffered)
                where n % 2 == 0
                select ExpensiveFunc(n);
Dim scanlines = From n In nums.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered)
                Where n Mod 2 = 0
                Select ExpensiveFunc(n)

Para ver o exemplo completo, confira Como especificar opções de mesclagem em PLINQ.

Se a consulta em questão não oferecer suporte à opção solicitada, a opção será ignorada. Na maioria dos casos, você não precisa especificar uma opção de mesclagem para uma consulta PLINQ. No entanto, em alguns casos você pode achar, ao testar e medir, que uma consulta terá uma melhor execução em um modo diferente do padrão. Uma forma comum de usar essa opção é forçando um operador de mesclagem de blocos a transmitir os resultados para fornecer uma interface de usuário mais ágil na resposta.

ParallelMergeOptions

A enumeração ParallelMergeOptions inclui as seguintes opções que especificam, para formas de consulta com suporte, como a saída final da consulta será produzida quando os resultados forem consumidos em um thread:

  • Not Buffered

    A opção NotBuffered faz com que cada elemento processado seja retornado de cada thread assim que ele for produzido. Esse comportamento é semelhante a fazer "streaming" da saída. Se o operador AsOrdered estiver presente na consulta, NotBuffered preservará a ordem dos elementos de origem. Embora NotBuffered comece a produzir resultados assim que estiverem disponíveis, o tempo total para produzir todos os resultados ainda poderá ser maior do que usar uma das outras opções de mesclagem.

  • Auto Buffered

    A opção AutoBuffered faz com que a consulta colete elementos em um buffer e, em seguida, gere periodicamente todo o conteúdo do buffer de uma vez para o thread de consumo. Isso equivale a gerar os dados de origem em "partes" em vez de usar o comportamento de "streaming" de NotBuffered. AutoBuffered pode demorar mais do que NotBuffered para disponibilizar o primeiro elemento no thread de consumo. O tamanho do buffer e o comportamento exato do retorno não são configuráveis e podem variar dependendo de vários fatores relacionados à consulta.

  • FullyBuffered

    A opção FullyBuffered faz com que a saída de toda a consulta seja armazenada em buffer antes que qualquer um dos elementos seja gerado. Quando você usa essa opção, pode demorar mais tempo para que o primeiro elemento fique disponível no thread de consumo, mas os resultados completos podem ainda ser produzidos mais rapidamente em comparação com as outras opções.

Operadores de consulta que dão suporte a opções de mesclagem

A tabela a seguir lista os operadores que dão suporte a todos os modos de opções de mesclagem sujeitos às restrições especificadas.

Operador Restrições
AsEnumerable Nenhum
Cast Nenhum
Concat Consultas não ordenadas que têm apenas uma fonte de dados de Matriz ou Lista.
DefaultIfEmpty Nenhum
OfType Nenhum
Reverse Consultas não ordenadas que têm apenas uma fonte de dados de Matriz ou Lista.
Select Nenhum
SelectMany Nenhum
Skip Nenhum
Take Nenhum
Where Nenhum

Todos os outros operadores da consulta PLINQ podem ignorar opções de mesclagem fornecidas pelo usuário. Alguns operadores de consulta, por exemplo, Reverse e OrderBy, não conseguem gerar elementos até que todos eles sejam produzidos e reordenados. Portanto, quando ParallelMergeOptions é usado em uma consulta que também contém um operador, como Reverse, o comportamento de mesclagem não será aplicado à consulta até que esse operador produza seus resultados.

A capacidade de alguns operadores para lidar com as opções de mesclagem depende do tipo da sequência de origem e se o operador AsOrdered foi usado anteriormente na consulta. ForAll é sempre NotBuffered; ele suspende seus elementos imediatamente. OrderBy é sempre FullyBuffered; ele precisa classificar a lista inteira antes de suspendê-la.

Confira também