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 membrosIEnumerable<Int32>
retornado pelo Enumerable.Range método.localInit
ou 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
, umAction<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 seuAction<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