Share via


如何:编写具有线程局部变量的 Parallel.ForEach 循环

下面的代码演示如何编写使用线程本地变量的 ForEach 方法。 当 ForEach 循环执行时,它会将其源集合划分为多个分区。 每个分区都将获得自己的“线程本地”变量的副本。 (术语“线程本地”在此处不太准确,因为在某些情况下两个分区可能在同一线程上运行。)

此示例中的代码和参数非常类似于对应的 For 方法。 有关更多信息,请参见如何:编写具有线程本地变量的 Parallel.For 循环

示例

若要在 ForEach 循环中使用线程本地变量,您必须使用采用两个 type 参数的方法版本。 第一个参数指定源元素的类型,第二个参数指定线程本地变量的类型。

第一个输入参数是数据源,第二个输入参数是对线程本地变量进行初始化的函数。 第三个输入参数是 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 中的 Lambda 表达式