• C# 多线程 Parallel.For 和 For 谁的效率高?那么 Parallel.ForEach 和 ForEach 呢?


    还是那句话:十年河东,十年河西,莫欺少年穷。

    今天和大家探讨一个问题:Parallel.For 和 For 谁的效率高呢?

    从CPU使用方面而言,Parallel.For 属于多线程范畴,可以开辟多个线程使用CPU内核,也就是说可以并行处理程序。For 循环是单线程的,一个线程执行完所有循环。

    因此你会认为:多线程的效率肯定高于单线程。但这样认为是错误的!

    例如下面程序:

    static void Main(string[] args)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
    
                ParallelLoopResult result =
                Parallel.For(0, 10000, i =>
                {
                    Console.Write("");
    
                });
                sw.Stop();
                TimeSpan ts2 = sw.Elapsed;
                Console.WriteLine("Parallel.For总共花费{0}ms.", ts2.TotalMilliseconds);
    
                //
                Stopwatch sw_Eq = new Stopwatch();
                sw_Eq.Start();
                for (int i = 0; i < 10000; i++)
                {
                    Console.Write(""); 
                }
                sw_Eq.Stop();
                TimeSpan tssw_Eq = sw_Eq.Elapsed;
                Console.WriteLine("for总共花费{0}ms.", tssw_Eq.TotalMilliseconds);
                Console.ReadKey();
            }

    额,为什么For 循环要比Parallel.For 效率要高呢?

    这是因为循环体内执行的任务开销太小,仅仅是输出一个空字符串而已。微软的文章已经指出任务的开销大小对并行任务的影响。如果任务很小,那么由于并行管理的附加开销(任务分配,调度,同步等成本),可能并行执行并不是优化方案。这也是上述程序For效率高出的原因。

    如果在循环体内执行向数据库插入操作,那么Parallel.For 效率就会高出,在此,我们认为每向数据库插入一条记录花费1毫秒时间,将程序修改如下:

    class Program
        {
            static void Main(string[] args)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
    
                ParallelLoopResult result =
                Parallel.For(0, 10, i =>
                {
                    Console.Write("");
                    Thread.Sleep(1);
    
                });
                sw.Stop();
                TimeSpan ts2 = sw.Elapsed;
                Console.WriteLine("Parallel.For总共花费{0}ms.", ts2.TotalMilliseconds);
    
                //
                Stopwatch sw_Eq = new Stopwatch();
                sw_Eq.Start();
                for (int i = 0; i < 10; i++)
                {
                    Console.Write("");
                    Thread.Sleep(1);
                }
                sw_Eq.Stop();
                TimeSpan tssw_Eq = sw_Eq.Elapsed;
                Console.WriteLine("for总共花费{0}ms.", tssw_Eq.TotalMilliseconds);
                Console.ReadKey();
            }
        }
    }

    执行结果大大改变:

    相信到此,大家应该明白了吧!也就说For是同步,Parallel.For 是异步执行。当然,我们也可以使用Thread实现异步编程:

    代码如下:

      class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("主线程测试开始..");
                Thread th = new Thread(ThMethod);
                th.Start();
                Thread.Sleep(1000);
                Console.WriteLine("主线程测试结束..");
                Console.ReadLine();
            }
    
    
            static void ThMethod()
            {
                Console.WriteLine("异步执行开始");
                for (int i = 0; i < 5; i++)
                {
                    Console.WriteLine("异步执行" + i.ToString() + "..");
                    Thread.Sleep(1000);
                }
                Console.WriteLine("异步执行完成");
            }
        }

    Parallel.ForEach 和 ForEach  与 Parallel.For 和 For 一样,一个是异步执行,开辟多个线程。一个是同步执行,开辟一个线程。因此,效率方面同上,主要看执行的什么任务,在此不作具体说明。

    下面写了一些代码,从下面的代码中我们可以看出Parallel.ForEach具体开辟了几个线程,如下:

    class Program
        {
            static void Main(string[] args)
            {
                int[] intList = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                ParallelLoopResult result = Parallel.ForEach(intList, (s,pls,longs) =>
                {
                    Console.WriteLine(longs + "  " + s);
                    pls.Stop();
                    if (pls.IsStopped)
                    {
                        Parallel.Invoke(Gs,Ks);//异步调用多个方法
                    }
                });
                Console.ReadKey();
            }
    
            public static void Gs()
            {
                Console.WriteLine("异步方法1");
            }
    
            public static void Ks()
            {
                Console.WriteLine("异步方法2");
            }
        }

    上述代码中,调用了Stop()方法,我们都知道,如果是同步执行的,调用Stop()后,会立即停止执行,那么程序只会输出索引值为0的结果。而在异步中不是这样的,异步迭代是多线程且没有顺序的。其执行结果如下:

    多次执行的结果可能不同。

    如上图所示,第一个图开辟了三个线程,执行顺序为 0 2 1,第二个图开辟了两个线程,执行顺序为:1 0 

    下面的Invoke()方法是异步调用其他的方法,在此不作解释,可参考C# Invoke()

    设置开启的线程的个数:

      Parallel.ForEach(NameArray,new ParallelOptions{MaxDegreeOfParallelism=3},(item,pls,i)=>
                {
                   
               });

    @陈卧龙的博客

  • 相关阅读:
    Taro 自定义组件样式不生效及解决方案
    Taro 实现多行文本溢出省略效果
    taro路由传参this.$router.params获取不到值
    taro版本切换及报错解决
    fabricjs实现图片加备注文字并下载效果
    html2canvas实现DOM导出为图片(入门)
    [Vue warn]: Error in render: "TypeError: Cannot read property 'length' of null"
    svn识别不出修改的文件
    prefer-object-spread
    JAVA学习(一)——基本语法
  • 原文地址:https://www.cnblogs.com/chenwolong/p/ParallelFor.html
Copyright © 2020-2023  润新知