Condividi tramite


Procedura: scrivere un ciclo Parallel.ForEach con variabili di thread locali

Nell'esempio seguente viene illustrato come scrivere un metodo ForEach che utilizza variabili di thread locali. Quando viene eseguito un ciclo ForEach, l'insieme di origine viene suddiviso in più partizioni. Per ogni partizione sarà disponibile una copia della variabile di thread locale. L'espressione "di thread locale" non è del tutto precisa in questo contesto, in quanto esistono casi in cui due partizioni possono essere eseguite sullo stesso thread.

Il codice e i parametri utilizzati in questo esempio sono molto simili al metodo For corrispondente. Per ulteriori informazioni, vedere Procedura: scrivere un ciclo Parallel.For con variabili locali dei thread.

Esempio

Per utilizzare una variabile di thread locale in un ciclo ForEach, è necessario utilizzare la versione del metodo che accetta due parametri type. Il primo parametro specifica il tipo di elemento di origine, mentre il secondo specifica il tipo di variabile di thread locale.

Il primo parametro di input è l'origine dati, mentre il secondo è la funzione che inizializzerà la variabile di thread locale. Il terzo parametro di input è un elemento Func<T1, T2, T3, TResult> richiamato dal ciclo parallelo su ogni iterazione. Quando l'utente fornisce il codice per il delegato, il ciclo passa nei parametri di input. I parametri di input sono l'elemento corrente, una variabile ParallelLoopState che consente di esaminare lo stato del ciclo e la variabile di thread locale. Quando l'utente restituisce la variabile di thread locale, il metodo la passa all'iterazione successiva su questa partizione. Questa variabile è distinta su tutte le partizioni del ciclo.

L'ultimo parametro di input del metodo ForEach è il delegato Action<T> che verrà richiamato dal metodo al completamento di tutti i cicli. Il metodo fornisce il valore finale della variabile di thread locale per questo thread (o partizione del ciclo) e l'utente fornisce il codice che acquisisce il valore finale ed esegue qualsiasi azione necessaria per combinare il risultato di questa partizione con i risultati di altre partizioni. Dal momento che il tipo di delegato è Action<T>, non esiste un valore restituito.

' 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();
        }
    }
}

Vedere anche

Attività

Procedura: scrivere un ciclo Parallel.For con variabili locali dei thread

Concetti

Parallelismo dei dati (Task Parallel Library)

Espressioni lambda in PLINQ e TPL