Compartir a través de


Cómo: Escribir un bucle Parallel.ForEach que tenga variables locales de subproceso

En el siguiente ejemplo se muestra cómo escribir un método ForEach que utiliza variables locales de subproceso. Cuando un bucle ForEach se ejecuta, divide su colección de origen en varias particiones. Cada partición obtendrá su propia copia de la variable "local de subproceso". (El término "local de subproceso" es ligeramente inexacto, porque en algunos casos dos particiones se pueden ejecutar en el mismo subproceso).

El código y los parámetros de este ejemplo se parecen mucho al método For correspondiente. Para obtener más información, vea Cómo: Escribir un bucle Parallel.For que tenga variables locales de subproceso.

Ejemplo

Para utilizar una variable local de subproceso en un bucle ForEach, debe utilizar la versión del método que toma dos parámetros type. El primer parámetro especifica el tipo del elemento de origen y el segundo parámetro especifica el tipo de la variable local de subproceso.

El primer parámetro de entrada es el origen de datos y el segundo es la función que inicializará la variable local de subproceso. El tercer parámetro de entrada es un Func<T1, T2, T3, TResult> que invoca el bucle paralelo en cada iteración. Se proporciona el código para el delegado y el bucle pasa los parámetros de entrada. Los parámetros de entrada son el elemento vigente, una variable ParallelLoopState que permite examinar el estado del bucle, y la variable local de subproceso. Devuelve la variable local de subproceso y, a continuación, el método pasa a la iteración siguiente de esta partición. Esta variable es distinta en todas las particiones del bucle.

El último parámetro de entrada del método ForEach es el delegado Action<T> que el método invocará cuando todos los bucles se hayan completado. El método proporciona el valor final de la variable local de subproceso para este subproceso (o partición del bucle) y proporciona el código que captura el valor final y realiza cualquier acción necesaria para combinar el resultado de esta partición con los resultados de las otras particiones. Como el tipo de delegado es Action<T>, no hay valor devuelto.

' 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 paramemter is the type of the source elements
        ' Second type parameter is the type of the local data (subtotal)
        Parallel.ForEach(Of Integer, Long)(nums, Function() 0,
                                           Function(elem, loopState, subtotal)
                                               subtotal += nums(elem)
                                               Return subtotal
                                           End Function,
                                            Sub(finalResult)
                                                Interlocked.Add(total, finalResult)
                                            End Sub)

        Console.WriteLine("The result of Parallel.ForEach is {0}", total)
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
    End Sub
End Module
namespace ThreadLocalForEach
{
    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 local data (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 += nums[j]; //modify local variable
                                            return subtotal; // value to be passed to next iteration
                                        },
                // Method to be executed when all loops have completed.
                // finalResult is the final value of subtotal. supplied by the ForEach method.
                                        (finalResult) => Interlocked.Add(ref total, finalResult)
                                        );

            Console.WriteLine("The total from Parallel.ForEach is {0}", total);
            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    }
}

Vea también

Tareas

Cómo: Escribir un bucle Parallel.For que tenga variables locales de subproceso

Conceptos

Paralelismo de datos (Task Parallel Library)

Expresiones lambda en PLINQ y TPL