Procedura: Scrivere un ciclo Parallel.For con variabili di thread localiHow to: Write a Parallel.For Loop with Thread-Local Variables

Questo esempio illustra come usare le variabili locali di thread per archiviare e recuperare lo stato in ogni attività separata creata da un ciclo For.This example shows how to use thread-local variables to store and retrieve state in each separate task that is created by a For loop. L'uso dei dati locali di thread permette di evitare il sovraccarico dovuto alla sincronizzazione di un numero elevato di accessi a uno stato condiviso.By using thread-local data, you can avoid the overhead of synchronizing a large number of accesses to shared state. Invece di scrivere in una risorsa condivisa a ogni iterazione, si calcola e si archivia il valore fino al completamento di tutte le iterazioni per l'attività.Instead of writing to a shared resource on each iteration, you compute and store the value until all iterations for the task are complete. È quindi possibile scrivere il risultato finale una volta sola nella risorsa condivisa oppure passarlo a un altro metodo.You can then write the final result once to the shared resource, or pass it to another method.

EsempioExample

L'esempio seguente chiama il metodo For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) per calcolare la somma dei valori in una matrice contenente un milione di elementi.The following example calls the For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) method to calculate the sum of the values in an array that contains one million elements. Il valore di ogni elemento è uguale all'indice corrispondente.The value of each element is equal to its index.

using System;
using System.Collections.Generic;
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;

        // Use type parameter to make subtotal a long, not an int
        Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
        {
            subtotal += nums[j];
            return subtotal;
        },
            (x) => Interlocked.Add(ref total, x)
        );

        Console.WriteLine("The total is {0:N0}", total);
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}
'How to: Write a Parallel.For Loop That Has Thread-Local Variables

Imports System.Threading
Imports System.Threading.Tasks

Module ForWithThreadLocal

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

        ' Use type parameter to make subtotal a Long type. Function will overflow otherwise.
        Parallel.For(Of Long)(0, nums.Length, Function() 0, Function(j, [loop], subtotal)
                                                                subtotal += nums(j)
                                                                Return subtotal
                                                            End Function, Function(x) Interlocked.Add(total, x))

        Console.WriteLine("The total is {0:N0}", total)
        Console.WriteLine("Press any key to exit")
        Console.ReadKey()
    End Sub

End Module

I primi due parametri di ogni metodo For specificano i valori di iterazione iniziali e finali.The first two parameters of every For method specify the beginning and ending iteration values. In questo overload del metodo, il terzo parametro corrisponde alla posizione di inizializzazione dello stato locale.In this overload of the method, the third parameter is where you initialize your local state. In questo contesto lo stato locale indica una variabile la cui durata si estende da immediatamente prima della prima iterazione del ciclo nel thread corrente a immediatamente dopo l'ultima iterazione.In this context, local state means a variable whose lifetime extends from just before the first iteration of the loop on the current thread, to just after the last iteration.

Il tipo del terzo parametro è Func<TResult>, dove TResult indica il tipo della variabile in cui sarà archiviato lo stato locale di thread.The type of the third parameter is a Func<TResult> where TResult is the type of the variable that will store the thread-local state. Il tipo corrispondente è definito dall'argomento di tipo generico fornito quando si chiama il metodo For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) generico, che in questo caso è Int64.Its type is defined by the generic type argument supplied when calling the generic For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) method, which in this case is Int64. L'argomento tipo indica al compilatore il tipo di variabile temporanea che sarà usata per l'archiviazione dello stato locale di thread.The type argument tells the compiler the type of the temporary variable that will be used to store the thread-local state. In questo esempio l'espressione () => 0 (o Function() 0 in Visual Basic) inizializza la variabile locale di thread su zero.In this example, the expression () => 0 (or Function() 0 in Visual Basic) initializes the thread-local variable to zero. Se un argomento di tipo generico è un tipo di riferimento o un tipo di valore definito dall'utente, l'espressione avrà un aspetto analogo al seguente:If the generic type argument is a reference type or user-defined value type, the expression would look like this:

() => new MyClass()  
Function() new MyClass()  

Il quarto parametro definisce la logica del ciclo.The fourth parameter defines the loop logic. Deve essere un delegato o un'espressione lambda con firma Func<int, ParallelLoopState, long, long> in C# o Func(Of Integer, ParallelLoopState, Long, Long) in Visual Basic.It must be a delegate or lambda expression whose signature is Func<int, ParallelLoopState, long, long> in C# or Func(Of Integer, ParallelLoopState, Long, Long) in Visual Basic. Il primo parametro è il valore del contatore di cicli per quell'iterazione del ciclo.The first parameter is the value of the loop counter for that iteration of the loop. Il secondo è un oggetto ParallelLoopState che può essere usato per uscire dal ciclo. L'oggetto è fornito dalla classe Parallel a ogni occorrenza del ciclo.The second is a ParallelLoopState object that can be used to break out of the loop; this object is provided by the Parallel class to each occurrence of the loop. Il terzo parametro è la variabile locale di thread.The third parameter is the thread-local variable. L'ultimo parametro è il tipo restituito.The last parameter is the return type. In questo caso il tipo è Int64, poiché questo è il tipo specificato nell'argomento di tipo For.In this case, the type is Int64 because that is the type we specified in the For type argument. Questa variabile è denominata subtotal ed è restituita dall'espressione lambda.That variable is named subtotal and is returned by the lambda expression. Il valore restituito è usato per inizializzare subtotal in ogni iterazione successiva del ciclo.The return value is used to initialize subtotal on each subsequent iteration of the loop. È anche possibile considerare quest'ultimo parametro come un valore passato a ogni iterazione e quindi passato al delegato localFinally al completamento dell'ultima iterazione.You can also think of this last parameter as a value that is passed to each iteration, and then passed to the localFinally delegate when the last iteration is complete.

Il quinto parametro definisce il metodo chiamato una volta, dopo il completamento di tutte le iterazioni in un determinato thread.The fifth parameter defines the method that is called once, after all the iterations on a particular thread have completed. Il tipo di argomento di input corrisponde di nuovo all'argomento di tipo del metodo For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) e al tipo restituito dall'espressione lambda del corpo.The type of the input argument again corresponds to the type argument of the For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) method and the type returned by the body lambda expression. In questo esempio il valore è aggiunto a una variabile nell'ambito delle classi in un modo thread-safe chiamando il metodo Interlocked.Add.In this example, the value is added to a variable at class scope in a thread safe way by calling the Interlocked.Add method. L'uso di una variabile locale di thread permette di evitare di scrivere nella variabile della classe a ogni iterazione del ciclo.By using a thread-local variable, we have avoided writing to this class variable on every iteration of the loop.

Per altre informazioni su come usare le espressioni lambda, vedere Espressioni lambda in PLINQ e TPL.For more information about how to use lambda expressions, see Lambda Expressions in PLINQ and TPL.

Vedere ancheSee also