方法: スレッド ローカル変数を持つ Parallel.ForEach ループを記述する

スレッド ローカル変数を持つ ForEach メソッドを記述する方法を次の例に示します。 ForEach ループが実行されると、そのソース コレクションが複数のパーティションに分割されます。 各パーティションには、"スレッド ローカル" 変数が個別にコピーされます ("スレッド ローカル" という用語は少し不正確です。1 つのスレッド上で 2 つのパーティションが実行されることがあるからです)。

この例のコードおよびパラメーターは、対応する For メソッドによく似ています。 詳細については、「方法: スレッド ローカル変数を持つ Parallel.For ループを記述する」を参照してください。

使用例

ForEach ループでスレッド ローカル変数を使用するには、2 つの type パラメーターを受け取る形式のメソッドを使用する必要があります。 最初のパラメーターではソース要素の型を指定し、2 番目のパラメーターではスレッド ローカル変数の型を指定します。

最初の入力パラメーターはデータ ソースで、2 番目の入力パラメーターはスレッド ローカル変数を初期化する関数です。 3 番目の入力パラメーターは、反復処理ごとに平行ループで呼び出される Func<T1, T2, T3, TResult> です。 プログラマはデリゲートのコードを作成します。入力パラメーターはループから渡されます。 入力パラメーターは、現在の要素、ループの状態のチェックに使用できる ParallelLoopState 変数、およびスレッド ローカル変数です。 プログラマはスレッド ローカル変数を返します。メソッドは、そのスレッド ローカル変数をこのパーティションの次の反復処理に渡します。 この変数はすべてのループ パーティションで異なります。

ForEach メソッドの最後の入力パラメーターは、すべてのループが完了したときにメソッドによって呼び出される Action<T> デリゲートです。 メソッドは、このスレッド (ループ パーティション) のスレッド ローカル変数の最終値を返します。プログラマは、その最終値をキャプチャして、このパーティションの結果と他のパーティションの結果を連結するコードを作成します。 デリゲート型は Action<T> であるため、戻り値はありません。

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

参照

処理手順

方法: スレッド ローカル変数を持つ Parallel.For ループを記述する

概念

データの並列化 (タスク並列ライブラリ)

PLINQ および TPL のラムダ式