Procédure : écrire une boucle Parallel.For avec des variables locales de threadHow to: Write a Parallel.For Loop with Thread-Local Variables

Cet exemple montre comment utiliser des variables de thread local pour stocker et récupérer l’état de chaque tâche créée par une boucle 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. En utilisant des données de thread local, vous pouvez éviter la surcharge liée à la synchronisation d'un grand nombre d'accès à un état partagé.By using thread-local data, you can avoid the overhead of synchronizing a large number of accesses to shared state. Au lieu d'écrire dans une ressource partagée à chaque itération, vous calculez et stockez la valeur jusqu'à ce que toutes les itérations de la tâche soient terminées.Instead of writing to a shared resource on each iteration, you compute and store the value until all iterations for the task are complete. Vous pouvez ensuite écrire une fois le résultat final dans la ressource partagée ou le transmettre à une autre méthode.You can then write the final result once to the shared resource, or pass it to another method.

ExempleExample

L'exemple suivant appelle la méthode For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) pour calculer la somme des valeurs d'un tableau qui contient un million d'éléments.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. La valeur de chaque élément est égale à son index.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

Les deux premiers paramètres de chaque méthode For spécifient les valeurs d'itération initiale et finale.The first two parameters of every For method specify the beginning and ending iteration values. Dans cette surcharge de la méthode, le troisième paramètre indique où vous initialisez votre état local.In this overload of the method, the third parameter is where you initialize your local state. Dans ce contexte, « état local » signifie une variable dont la durée de vie commence juste avant la première itération de la boucle sur le thread actuel et se termine juste après la dernière itération.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.

Le type du troisième paramètre est un délégué Func<TResult>TResult représente le type de la variable destinée à stocker l'état de thread local.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. Son type est défini par l'argument de type générique fourni au moment de l'appel de la méthode For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) générique, en l'occurrence 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’argument de type indique au compilateur le type de la variable temporaire à utiliser pour stocker l’état de thread local.The type argument tells the compiler the type of the temporary variable that will be used to store the thread-local state. Dans cet exemple, l'expression () => 0 (ou Function() 0 dans Visual Basic) initialise la variable de thread local à zéro.In this example, the expression () => 0 (or Function() 0 in Visual Basic) initializes the thread-local variable to zero. Si l'argument de type générique est un type de référence ou un type de valeur défini par l'utilisateur, l'expression ressemble à ceci :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()  

Le quatrième paramètre définit la logique de la boucle.The fourth parameter defines the loop logic. Il doit correspondre à un délégué ou à une expression lambda dont la signature est Func<int, ParallelLoopState, long, long> en C# ou Func(Of Integer, ParallelLoopState, Long, Long) en 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. Le premier paramètre est la valeur du compteur de boucle pour cette itération de la boucle.The first parameter is the value of the loop counter for that iteration of the loop. Le deuxième est un objet ParallelLoopState qui permet de quitter la boucle ; cet objet est fourni par la classe Parallel à chaque occurrence de la boucle.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. Le troisième paramètre est la variable de thread local.The third parameter is the thread-local variable. Le dernier paramètre est le type de retour.The last parameter is the return type. Dans ce cas, le type est Int64, car c'est ce type que nous avons spécifié dans l'argument de type For.In this case, the type is Int64 because that is the type we specified in the For type argument. Cette variable est nommée subtotal et est retournée par l'expression lambda.That variable is named subtotal and is returned by the lambda expression. La valeur de retour est utilisée pour initialiser subtotal à chaque itération suivante de la boucle.The return value is used to initialize subtotal on each subsequent iteration of the loop. Vous pouvez également considérer ce dernier paramètre comme une valeur transmise à chaque itération, puis communiquée au délégué localFinally quand la dernière itération est terminée.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.

Le cinquième paramètre définit la méthode qui est appelée une fois, après la fin de toutes les itérations sur un thread particulier.The fifth parameter defines the method that is called once, after all the iterations on a particular thread have completed. Le type de l'argument d'entrée correspond de nouveau à l'argument de type de la méthode For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) et au type retourné par l'expression lambda du corps.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. Dans cet exemple, la valeur est ajoutée à une variable à portée de classe d'une façon thread-safe en appelant la méthode 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'utilisation d'une variable de thread local nous a évité d'écrire dans cette variable de classe à chaque itération de la boucle.By using a thread-local variable, we have avoided writing to this class variable on every iteration of the loop.

Pour plus d’informations sur l’utilisation d’expressions lambda, consultez Expressions lambda en PLINQ et dans la bibliothèque parallèle de tâches.For more information about how to use lambda expressions, see Lambda Expressions in PLINQ and TPL.

Voir aussiSee also