Partilhar via


Como: Escrever um loop Parallel.ForEach com variáveis de partição local

O exemplo a seguir mostra como escrever um ForEach método que usa variáveis de partição local. Quando um ForEach loop é executado, ele divide sua coleção de código-fonte em várias partições. Cada partição tem sua própria cópia da variável partição-local. Uma variável partition-local é semelhante a uma variável thread-local, exceto que várias partições podem ser executadas em um único thread.

O código e os parâmetros neste exemplo se assemelham muito ao método correspondente For . Para obter mais informações, consulte Como escrever um loop Parallel.For com variáveis Thread-Local.

Para usar uma variável partição-local em um ForEach loop, você deve chamar uma das sobrecargas de método que usa dois parâmetros de tipo. O primeiro parâmetro type, TSource, especifica o tipo do elemento source, e o segundo parâmetro type, TLocal, especifica o tipo da variável partition-local.

Exemplo

O exemplo a seguir chama a Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) sobrecarga para calcular a soma de uma matriz de um milhão de elementos. Esta sobrecarga tem quatro parâmetros:

  • source, que é a fonte de dados. Deve implementar IEnumerable<T>. A fonte de dados em nosso exemplo é o objeto de um milhão de membros IEnumerable<Int32> retornado pelo Enumerable.Range método.

  • localInitou a função que inicializa a variável partição-local. Esta função é chamada uma vez para cada partição em que a Parallel.ForEach operação é executada. Nosso exemplo inicializa a variável partition-local como zero.

  • body, a Func<T1,T2,T3,TResult> que é invocado pelo loop paralelo em cada iteração do loop. A sua assinatura é Func\<TSource, ParallelLoopState, TLocal, TLocal>. Você fornece o código para o delegado, e o loop passa nos parâmetros de entrada, que são:

    • O elemento atual do IEnumerable<T>.

    • Uma ParallelLoopState variável que você pode usar no código do delegado para examinar o estado do loop.

    • A variável partição-local.

    Seu delegado retorna a variável partição-local, que é então passada para a próxima iteração do loop que é executado nessa partição específica. Cada partição de loop mantém uma instância separada dessa variável.

    No exemplo, o delegado adiciona o valor de cada inteiro à variável partição-local, que mantém um total em execução dos valores dos elementos inteiros nessa partição.

  • localFinally, um Action<TLocal> delegado que o Parallel.ForEach invoca quando as operações de looping em cada partição foram concluídas. O Parallel.ForEach método passa ao seu Action<TLocal> delegado o valor final da variável partição-local para essa partição de loop e você fornece o código que executa a ação necessária para combinar o resultado dessa partição com os resultados das outras partições. Este delegado pode ser invocado simultaneamente por várias tarefas. Por isso, o exemplo usa o método para sincronizar o Interlocked.Add(Int32, Int32) acesso à total variável. Como o tipo de delegado é um Action<T>, não há valor de retorno.

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        int[] nums = Enumerable.Range(0, 1000000).ToArray();
        long total = 0;

        // First type parameter is the type of the source elements
        // Second type parameter is the type of the thread-local variable (partition subtotal)
        Parallel.ForEach<int, long>(
            nums, // source collection
            () => 0, // method to initialize the local variable
            (j, loop, subtotal) => // method invoked by the loop on each iteration
            {
                subtotal += j; //modify local variable
                return subtotal; // value to be passed to next iteration
            },
            // Method to be executed when each partition has completed.
            // finalResult is the final value of subtotal for a particular partition.
            (finalResult) => Interlocked.Add(ref total, finalResult));

        Console.WriteLine("The total from Parallel.ForEach is {0:N0}", total);
    }
}
// The example displays the following output:
//        The total from Parallel.ForEach is 499,999,500,000
' How to: Write a Parallel.ForEach Loop That Has Thread-Local Variables

Imports System.Threading
Imports System.Threading.Tasks

Module ForEachThreadLocal
    Sub Main()

        Dim nums() As Integer = Enumerable.Range(0, 1000000).ToArray()
        Dim total As Long = 0

        ' First type parameter is the type of the source elements
        ' Second type parameter is the type of the thread-local variable (partition subtotal)
        Parallel.ForEach(Of Integer, Long)(nums, Function() 0,
                                           Function(elem, loopState, subtotal)
                                               subtotal += elem
                                               Return subtotal
                                           End Function,
                                            Sub(finalResult)
                                                Interlocked.Add(total, finalResult)
                                            End Sub)

        Console.WriteLine("The result of Parallel.ForEach is {0:N0}", total)
    End Sub
End Module
' The example displays the following output:
'       The result of Parallel.ForEach is 499,999,500,000

Consulte também