C# Parallel之for,foreach使用(笔记)

  C# 4.0 的新特性之并行库(TPL), 是 .NET Framework 4的 System.ThreadingSystem.Threading.Tasks 命名空间中的一组公共类型和 API,基本包含以下几点:

    1. Parallel.For - for 循环的并行运算 
    2. Parallel.ForEach - foreach 循环的并行运算 
    3. Parallel.Invoke - 并行调用多个任务 
    4. Task - 任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的
    5. PLINQ - 用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算

  今天先记录以下For,ForEach的基本使用,也是最常用到的。方便自己使用。

  1.如果遍历集合里面的元素,做没有关系的处理时:

    For:

public static class ParallelFor_narmal
    {
        // 每个之间独立,不需要交互
        public static void narmal()
        {
            int[] arry = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            Parallel.For(0,arry.Length,(i,loopstate)=>
            {
                Console.Out.WriteLine(arry[i]);
            });
        }
    }

    ForEach的情况差不多,这种情况是最简单的。其实也就可以使用泛型集合的ForEach(Action(T))方法了.

  2.如果集合里面的元素处理是有关联的,比如求和,但是并发是多线程的,按照传统的集合遍历肯定是有问题的,这个时候就需要了局部变量了。

    For: 

 public static long withlocalvariable() 
        {

           // int[] nums = Enumerable.Range(0, 1000000).ToArray();
            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
            long total = 0;
            object lockflg = new object();

            // Use type parameter to make subtotal a long, not an int
            // 带有局部变量的并发。
            // 第一个参数是for循环的起始迭代位置
            // 第二个参数是for循环的终了迭代位置
            // 第三个参数是局部变量的初始化。Func(T)。 这里就是给每个线程局部变量subtotal初始化为0;
            // 第四个参数就是每个线程的执行的方法体。原型为Func(int,ParallelLoopState,T,B),具有三个入力参数和一个返回值的代理。
            //                其中j是运行时自动提供的迭代值,loop是用来控制循环的中断,subtotal就是局部变量,最有有一个返回值。
            // 第五个参数为具有一个入力参数,没有返回值的代理Action(T),用来处理每个线程的返回的结果。因为是多线程处理,所有要注意线程安全
            Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
            {
                subtotal += nums[j];
                return subtotal;
            },
                (x) => 
                { //Interlocked.Add(ref total, x);
                    lock (lockflg)
                    {
                        total += x; 
                    }
                
                }
            );

            return total;
        }

    ForEach:

public static class ParallelForEach_WithLocalVariable
    {
        public static long withlocalvariable()
        {
            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
            long total = 0;
            object lockflg = new object();

            //  ForEach<int, long> 第一个参数指定源元素的类型,此处的j,第二个参数指定线程本地变量的类型,此处的subtotal
            Parallel.ForEach<int, long>(nums,  // 数据源
                                       () => 0, // subtotal初始化
                                       (j, loop, subtotal) =>{ subtotal +=j;return subtotal;}, // 每个线程执行的方法体
                                       (x) =>{lock (lockflg) { total += x; }});  // 处理每个结果

            return total;
        }
    }

      这两种情况是最长使用到了,其实还有更细致的控制操作,有兴趣的可以看看 数据并行(任务并行库)

原文地址:https://www.cnblogs.com/tangchd/p/3480246.html