C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解

C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解最近要做一个大数据dataTable循环操作,开始发现运用foreach,进行大数据循环,并做了一些逻辑处理。在循环中耗费的时间过长。后来换成使用Parallel.ForEach来进行循环。一开始认为, 数据比较大时,Parallel.ForEach肯定比 ForEach效率高,后来发现,其实并不是这样。我用了1000万次循环测试:{CSDN:CODE:2601125}

大家好,又见面了,我是你们的朋友全栈君。

      最近要做一个大数据dataTable循环操作,开始发现 运用foreach,进行大数据循环,并做了一些逻辑处理。在循环中耗费的时间过长。后来换成使用Parallel.ForEach来进行循环。 一开始认为, 数据比较大时,Parallel.ForEach肯定比 ForEach效率高,后来发现,其实并不是这样。

我用了1000万次循环测试:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
         
            Stopwatch Watch1 = new Stopwatch();
            Watch1.Start();
            List<entityA> source = new List<entityA>();
            for (int i = 0; i < 10000000; i++)
            {
                source.Add(new entityA
                {
                    name = "悟空" + i,
                    sex = i % 2 == 0 ? "男" : "女",
                    age = i
                });
            }
            Watch1.Stop();

            Console.WriteLine("list循环插入耗时:" + Watch1.ElapsedMilliseconds);
            Stopwatch Watch2 = new Stopwatch();
            Watch2.Start();
            loop1(source);
            Watch2.Stop();
            Console.WriteLine("一般for循环耗时:" + Watch2.ElapsedMilliseconds);

            Stopwatch Watch3 = new Stopwatch();
            Watch3.Start();
            loop2(source);
            Watch3.Stop();
            Console.WriteLine("一般foreach循环耗时:" + Watch3.ElapsedMilliseconds);


            Stopwatch Watch4 = new Stopwatch();
            Watch4.Start();
            loop3(source);
            Watch4.Stop();
            Console.WriteLine("并行for循环耗时:" + Watch4.ElapsedMilliseconds);

            Stopwatch Watch5 = new Stopwatch();
            Watch5.Start();
            loop4(source);
            Watch5.Stop();
            Console.WriteLine("并行foreach循环耗时:" + Watch5.ElapsedMilliseconds);
            Console.ReadLine();
        }
        //普通的for循环
        static void loop1(List<entityA> source)
        {
            int count = source.Count();
            for (int i = 0; i < count; i++)
            {
                source[0].age= + 10;
                //System.Threading.Thread.Sleep(10);
            }
        }

        //普通的foreach循环
        static void loop2(List<entityA> source)
        {
            foreach (entityA item in source)
            {
                item.age =+ 10;
                //System.Threading.Thread.Sleep(10);
            }
        }

        //并行的for循环
        static void loop3(List<entityA> source)
        {
            int count = source.Count();
            Parallel.For(0, count, item =>
            {
                //source[count].age= source[count].age + 10;
                //System.Threading.Thread.Sleep(10);
            });
        }

        //并行的foreach循环
        static void loop4(List<entityA> source)
        {
            Parallel.ForEach(source, item =>
            {
                item.age = item.age + 10;
                //System.Threading.Thread.Sleep(10);
            });
        }
    }


    //简单的实体
    class entityA
    {
        public string name { set; get; }
        public string sex { set; get; }
        public int age { set; get; }
    }
}

运行结果:

C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解

结果居然是并行比一般的循环还耗时,但这是为什么呢?

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

基于这一点,我们对程序进行调整,循环1000次,每次里面线程sleep(10),这样我们试试。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
         
            Stopwatch Watch1 = new Stopwatch();
            Watch1.Start();
            List<entityA> source = new List<entityA>();
            for (int i = 0; i < 1000; i++)
            {
                source.Add(new entityA
                {
                    name = "悟空" + i,
                    sex = i % 2 == 0 ? "男" : "女",
                    age = i
                });
            }
            Watch1.Stop();

            Console.WriteLine("list循环插入耗时:" + Watch1.ElapsedMilliseconds);
            Stopwatch Watch2 = new Stopwatch();
            Watch2.Start();
            loop1(source);
            Watch2.Stop();
            Console.WriteLine("一般for循环耗时:" + Watch2.ElapsedMilliseconds);

            Stopwatch Watch3 = new Stopwatch();
            Watch3.Start();
            loop2(source);
            Watch3.Stop();
            Console.WriteLine("一般foreach循环耗时:" + Watch3.ElapsedMilliseconds);


            Stopwatch Watch4 = new Stopwatch();
            Watch4.Start();
            loop3(source);
            Watch4.Stop();
            Console.WriteLine("并行for循环耗时:" + Watch4.ElapsedMilliseconds);

            Stopwatch Watch5 = new Stopwatch();
            Watch5.Start();
            loop4(source);
            Watch5.Stop();
            Console.WriteLine("并行foreach循环耗时:" + Watch5.ElapsedMilliseconds);
            Console.ReadLine();
        }
        //普通的for循环
        static void loop1(List<entityA> source)
        {
            int count = source.Count();
            for (int i = 0; i < count; i++)
            {
                source[0].age= + 10;
                System.Threading.Thread.Sleep(10);
            }
        }

        //普通的foreach循环
        static void loop2(List<entityA> source)
        {
            foreach (entityA item in source)
            {
                item.age =+ 10;
                System.Threading.Thread.Sleep(10);
            }
        }

        //并行的for循环
        static void loop3(List<entityA> source)
        {
            int count = source.Count();
            Parallel.For(0, count, item =>
            {
                //source[count].age= source[count].age + 10;
                System.Threading.Thread.Sleep(10);
            });
        }

        //并行的foreach循环
        static void loop4(List<entityA> source)
        {
            Parallel.ForEach(source, item =>
            {
                item.age = item.age + 10;
                System.Threading.Thread.Sleep(10);
            });
        }
    }


    //简单的实体
    class entityA
    {
        public string name { set; get; }
        public string sex { set; get; }
        public int age { set; get; }
    }
}

执行结果:

C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解

效率一目了然。

这样的结果认证了我们上面的结论。当我们在循环中执行时间过长时,我们需要采用并行循环,效率较高。当时间过短,我们需要用foreach和for.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/161789.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 树莓派是什么?能干什么?和单片机有什么区别?「建议收藏」

    树莓派是什么?能干什么?和单片机有什么区别?「建议收藏」什么是树莓派?树莓派是由树莓派基金会发布的卡片式电脑,起初的目的是为了让更多的孩子们可以学习计算机编程,但是发布以后受到了广大计算机爱好者的喜爱。树莓派被称为卡片式电脑,顾名思义它可以安装操作系统,并且接上显示屏鼠标键盘就可以正常使用,在上面可以用python或者C语言编程并运行。树莓派和单片机的区别?树莓派是卡片式电脑可以装操作系统,可以直接在上面编程并运行,而单片机是没有操作系统的它…

    2022年5月7日
  • 海量图片存储解决方案

    海量图片存储解决方案当今世界,互联网、大数据应用迅猛发展,物联网、人工智能、云计算技术日新月异,随之而来的是各种企业和个人应用持续不断地产生亿级甚至是百亿级的海量小文件。这些小文件的元数据管理、存储性能以及访问效率等问题因而成为学术界和工业界公认的难题。例如,国内目前最大的电商网站淘宝存储的商品图片超过200亿张,这些文件的平均大小仅为15KB左右,国外著名的社交网站Facebook存储的图片总量更是超…

    2022年7月12日
  • shadowrock端口被占用_打开端口失败怎么处理

    shadowrock端口被占用_打开端口失败怎么处理右键选择选项设置

    2022年9月3日
  • Python读取excel文件数据并插入数据库[通俗易懂]

    Python读取excel文件数据并插入数据库[通俗易懂]目的:将excel文件StudentInfo.xls的学生信息插入到test库中的student表中一、连接mysql数据库安装第三方库pymysql:pipinstallpymysql调用pymysql.connect()方法连接数据库,代码如下importpymysql#打开数据库连接conn=pymysql.connect(host=’localhost’,#MySQL服务器地址user=’root’,#MySQL服务器端口号p

    2022年9月1日
  • Spring的AOP实现原理

    Spring的AOP实现原理本学习笔记将尽可能的将AOP的知识讲解的通俗易懂,先从一个典型的问题出发,引入AOP这个概念,介绍AOP的基本概念,再到Spring中的AOP的实现方案,最后进行一个简单的总结归纳。本学习笔记中不考虑cglib、也不会太关注SpringAOP如何使用,而是尽可能的简单的说清楚AOP的工作原理。笔记中贴出的源代码均是Spring5.1.7-RELEASE版本问题提出如下代码块,现在需要统计这个方法执行的耗时情况publicvoidrunTask(){doSome

    2022年9月18日
  • php替换中文字符串,php如何替换字符串里的字符「建议收藏」

    php替换中文字符串,php如何替换字符串里的字符「建议收藏」php替换字符串里字符的方法:1、通过substr_replace函数把字符串的一部分替换为另一个字符串;2、使用str_replace函数将一个字符串替换字符串中的另一些字符。PHP字符串替换用于从字符串中替换指定字符串。相关函数如下:substr_replace():把字符串的一部分替换为另一个字符串str_replace():使用一个字符串替换字符串中的另一些字符substr_replac…

    2022年5月10日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号