Procedura: Scrivere un ciclo Parallel.ForEach con variabili partition-localHow to: Write a Parallel.ForEach loop with partition-local variables

L'esempio seguente illustra come scrivere un metodo ForEach che usa variabili partition-local.The following example shows how to write a ForEach method that uses partition-local variables. Quando viene eseguito un ciclo ForEach, la relativa raccolta di origine viene divisa in più partizioni.When a ForEach loop executes, it divides its source collection into multiple partitions. Ogni partizione ha la propria copia della variabile partition-local.Each partition has its own copy of the partition-local variable. Una variabile partition-local è simile a una variabile thread-local, tranne per il fatto che in un singolo thread possono essere eseguite più partizioni.A partition-local variable is similar to a thread-local variable, except that multiple partitions can run on a single thread.

Il codice e i parametri riportati in questo esempio, somigliano molto al metodo For corrispondente.The code and parameters in this example closely resemble the corresponding For method. Per altre informazioni, vedere Procedura: Scrivere un ciclo Parallel.For con variabili di thread locali.For more information, see How to: Write a Parallel.For Loop with Thread-Local Variables.

Per usare una variabile partition-local in un ciclo ForEach, è necessario chiamare uno degli overload del metodo che accetta due parametri di tipo.To use a partition-local variable in a ForEach loop, you must call one of the method overloads that takes two type parameters. Il primo parametro di tipo, TSource, specifica il tipo di elemento di origine, mentre il secondo parametro di tipo, TLocal, specifica il tipo di variabile partition-local.The first type parameter, TSource, specifies the type of the source element, and the second type parameter, TLocal, specifies the type of the partition-local variable.

EsempioExample

Nell'esempio seguente viene chiamato l'overload Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) per calcolare la somma di una matrice di un milione di elementi.The following example calls the Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) overload to compute the sum of an array of one million elements. L'overload ha quattro parametri:This overload has four parameters:

  • source, ovvero l'origine dati.source, which is the data source. Deve implementare IEnumerable<T>.It must implement IEnumerable<T>. L'origine dati nell'esempio è l'oggetto IEnumerable<Int32> da un milione di membri restituito dal metodo Enumerable.Range.The data source in our example is the one million member IEnumerable<Int32> object returned by the Enumerable.Range method.

  • localInit, ovvero la funzione che inizializza la variabile partition-local.localInit, or the function that initializes the partition-local variable. Questa funzione viene chiamata una volta per ogni partizione in cui viene eseguita l'operazione Parallel.ForEach.This function is called once for each partition in which the Parallel.ForEach operation executes. Nell'esempio, la variabile partition-local viene inizializzata su zero.Our example initializes the partition-local variable to zero.

  • body, un delegato Func<T1,T2,T3,TResult> che viene richiamato dal ciclo parallelo per ogni iterazione del ciclo.body, a Func<T1,T2,T3,TResult> that is invoked by the parallel loop on each iteration of the loop. La firma è Func\<TSource, ParallelLoopState, TLocal, TLocal>.Its signature is Func\<TSource, ParallelLoopState, TLocal, TLocal>. Si fornisce il codice per il delegato e il ciclo passa i parametri di input, che sono:You supply the code for the delegate, and the loop passes in the input parameters, which are:

    • L'elemento corrente dell'oggetto IEnumerable<T>.The current element of the IEnumerable<T>.

    • Una variabile ParallelLoopState che si può usare nel codice del delegato per esaminare lo stato del ciclo.A ParallelLoopState variable that you can use in your delegate's code to examine the state of the loop.

    • La variabile partition-local.The partition-local variable.

    Il delegato restituisce la variabile partition-local, che viene quindi passata all'iterazione successiva del ciclo che viene eseguito in quella partizione specifica.Your delegate returns the partition-local variable, which is then passed to the next iteration of the loop that executes in that particular partition. Ogni partizione del ciclo mantiene un'istanza separata di questa variabile.Each loop partition maintains a separate instance of this variable.

    Nell'esempio il delegato aggiunge il valore di ogni valore integer alla variabile partition-local, che mantiene un totale corrente dei valori degli elementi integer in quella partizione.In the example, the delegate adds the value of each integer to the partition-local variable, which maintains a running total of the values of the integer elements in that partition.

  • localFinally, un delegato Action<TLocal> che viene richiamato da Parallel.ForEach al termine delle operazioni di riproduzione del ciclo in ogni partizione.localFinally, an Action<TLocal> delegate that the Parallel.ForEach invokes when the looping operations in each partition have completed. Il metodo Parallel.ForEach passa al delegato Action<TLocal> il valore finale della variabile partition-local per questa partizione del ciclo e l'utente fornisce il codice che esegue l'azione necessaria per la combinazione del risultato di questa partizione con i risultati delle altre partizioni.The Parallel.ForEach method passes your Action<TLocal> delegate the final value of the partition-local variable for this loop partition, and you provide the code that performs the required action for combining the result from this partition with the results from the other partitions. Questo delegato può essere chiamato simultaneamente da più attività.This delegate can be invoked concurrently by multiple tasks. Per questo motivo, nell'esempio viene usato il metodo Interlocked.Add(Int32, Int32) per sincronizzare l'accesso alla variabile total.Because of this, the example uses the Interlocked.Add(Int32, Int32) method to synchronize access to the total variable. Poiché il tipo del delegato è Action<T>, non viene restituito alcun valore.Because the delegate type is an Action<T>, there is no return value.

 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 paramemter 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

Vedere ancheSee also