方法: パーティション ローカル変数を使用する Parallel.ForEach ループを記述するHow to: Write a Parallel.ForEach loop with partition-local variables

パーティション ローカル変数を使用する ForEach メソッドを記述する方法を次の例に示します。The following example shows how to write a ForEach method that uses partition-local variables. ForEach ループが実行されると、そのソース コレクションが複数のパーティションに分割されます。When a ForEach loop executes, it divides its source collection into multiple partitions. 各パーティションは、パーティション ローカル変数の独自のコピーを所有しています。Each partition has its own copy of the partition-local variable. パーティション ローカル変数は、1 つのスレッドに対して複数のパーティションを実行できる点を除き、スレッド ローカル変数と似ています。A partition-local variable is similar to a thread-local variable, except that multiple partitions can run on a single thread.

この例のコードおよびパラメーターは、対応する For メソッドによく似ています。The code and parameters in this example closely resemble the corresponding For method. 詳細については、「方法 :スレッド ローカル変数を使用する Parallel.For ループを記述する」を参照してください。For more information, see How to: Write a Parallel.For Loop with Thread-Local Variables.

ForEach ループでパーティション ローカル変数を使用するには、2 つのタイプのパラメーターを取るメソッド オーバーロードのうち、いずれか 1 つを呼び出す必要があります。To use a partition-local variable in a ForEach loop, you must call one of the method overloads that takes two type parameters. 最初の型パラメーター TSource でソース要素の型を指定し、2 番目の型パラメーター TLocal でパーティション ローカル変数の型を指定します。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.

Example

以下の例では、Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) のオーバーロードを呼び出して、100 万個の要素からなる配列の合計を計算します。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. このオーバーロードには、4 つのパラメータがあります。This overload has four parameters:

  • source。データ ソースです。source, which is the data source. これは、IEnumerable<T> を実装する必要があります。It must implement IEnumerable<T>. この例のデータ ソースは、IEnumerable<Int32> によって返される、100 万個のメンバーからなる Enumerable.Range オブジェクトです。The data source in our example is the one million member IEnumerable<Int32> object returned by the Enumerable.Range method.

  • localInit。またはパーティション ローカル変数を初期化する関数です。localInit, or the function that initializes the partition-local variable. この関数は、Parallel.ForEach 操作が実行される各パーティションで 1 回呼び出されます。This function is called once for each partition in which the Parallel.ForEach operation executes. この例では、パーティション ローカル変数がゼロに初期化されます。Our example initializes the partition-local variable to zero.

  • body。ループの各反復処理に対して並列ループで呼び出される Func<T1,T2,T3,TResult> です。body, a Func<T1,T2,T3,TResult> that is invoked by the parallel loop on each iteration of the loop. シグニチャは Func\<TSource, ParallelLoopState, TLocal, TLocal> です。Its signature is Func\<TSource, ParallelLoopState, TLocal, TLocal>. プログラマはデリゲートのコードを作成します。入力パラメーターはループから渡されます。これらの入力パラメーターは以下のとおりです。You supply the code for the delegate, and the loop passes in the input parameters, which are:

    • IEnumerable<T> の現在の要素。The current element of the IEnumerable<T>.

    • ParallelLoopState 変数。デリゲートのコードで、ループの状態を確認するために使用できます。A ParallelLoopState variable that you can use in your delegate's code to examine the state of the loop.

    • パーティション ローカル変数。The partition-local variable.

    デリゲートからパーティション ローカル変数が返されると、その変数は、その特定のパーティションで実行されるループの次の反復処理に渡されます。Your delegate returns the partition-local variable, which is then passed to the next iteration of the loop that executes in that particular partition. ループ パーティションごとに、この変数の個別のインスタンスが保持されます。Each loop partition maintains a separate instance of this variable.

    この例では、デリゲートによって個々の整数の値がパーティション ローカル変数に追加されます。スレッド ローカル変数には、そのパーティションで順次追加される整数要素の値の現在の合計が保持されます。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。各パーティションでのループ操作が完了した時点で、Action<TLocal> によって呼び出される Parallel.ForEach デリゲート。localFinally, an Action<TLocal> delegate that the Parallel.ForEach invokes when the looping operations in each partition have completed. Parallel.ForEach メソッドは、Action<TLocal> デリゲートに、このループ パーティションのパーティション ローカル変数の最終値を返します。プログラマは、このパーティションの結果と他のパーティションの結果を結合するために必要な操作を実行するコードを作成します。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. このデリゲートは、複数のタスクで同時に呼び出すことができます。This delegate can be invoked concurrently by multiple tasks. このため、この例では total 変数へのアクセスを同期するために Interlocked.Add(Int32, Int32) メソッドが使用されます。Because of this, the example uses the Interlocked.Add(Int32, Int32) method to synchronize access to the total variable. デリゲート型は Action<T> であるため、戻り値はありません。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

関連項目See also