from:https://blog.csdn.net/li315171406/article/details/78450534

最近要做一个大数据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; }
}
}

运行结果:

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

这是因为循环体内执行的任务开销太小,仅仅是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; }
}
}

执行结果:

效率一目了然。

这样的结果认证了我们上面的结论。当我们在循环中执行时间过长时,我们需要采用并行循环,效率较高。当时间过短,我们需要用foreach和for.
---------------------
作者:李江涛-Sir
来源:CSDN
原文:https://blog.csdn.net/li315171406/article/details/78450534
版权声明:本文为博主原创文章,转载请附上博文链接!

C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解的更多相关文章

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

    还是那句话:十年河东,十年河西,莫欺少年穷. 今天和大家探讨一个问题:Parallel.For 和 For 谁的效率高呢? 从CPU使用方面而言,Parallel.For 属于多线程范畴,可以开辟多个 ...

  2. php代码优化系列 -- array_walk 和 foreach, for 的效率的比较

    实验是我学习计算机科学的一个重要方法,计算机科学不是简单的智力游戏,它本质上来说不是一门科学,而是一个改造世界的工具.数学方法和实验方法是计算机研究的基本方法,也是我们学习的基本方法,数学锻炼我们的思 ...

  3. php代码优化 -- array_walk 和 foreach, for 的效率的比较

    <?php /** * array_walk 和 foreach, for 的效率的比较. * 我们要测试的是foreach, for, 和 array_walk的效率的问题. */ //产生一 ...

  4. C# for 和 foreach的执行效率

    for和foreach哪个执行效率快,相信很多人都会说当然是foreach快啊,在我实验之前我也是这么认为的,直到今天.费话不多说,下面是测试的结果,区分Debug和Release,数据采用int[] ...

  5. java8 for ,forEach ,lambda forEach , strean forEach , parller stream forEach, Iterator性能对比

    java8 for ,forEach ,Iterator,lambda forEach ,lambda  strean forEach , lambda parller stream forEach性 ...

  6. Parallel Programming-Paralle.For && ForEach

    本文主要介绍Parallel.For以及Parallel.ForEach.Parallel.For是普通步长为1的for循环的并行代替方案.Parallel.ForEach是以集合为基准进行循环的fo ...

  7. mybatis中foreach参数过多效率很慢的优化

    foreach 后面in 传入的参数有1万条,#和$是有效率区别的,$的效率远高于#,上篇文章做了比较. 但没达到我的理想结果. 1. 更改方式,把foreach 去掉,改成拼装方式, 参数直接拼装成 ...

  8. Foreach嵌套Foreach速度慢优化方案

    有时候这样的效率还可以,但是只要牵涉到操作数据库,那就GAMEOVER.. 最近在维护项目,一个Foreach循环,4分半才能出来结果. 代码: foreach ($content as $key = ...

  9. 多线程Parallel和Task

    不管是Parallel还是Task,最里面都是线程池(里面是线程)当开启多个任务后,系统会根据当前的线程池的资源进行分配,任务则进行等待Parallel可以对系统的CPU进行设置,可以最大程度上榨干系 ...

随机推荐

  1. openvpn之EasyRSA配置篇

    cd EasyRSA-2.2.2 vi vars #红色加粗的表示是我们需要修改的,其它的保持默认就可以 export EASY_RSA="`pwd`" export OPENSS ...

  2. 【html】param 以及 embed 的有关 flash 属性详解

    本文主要介绍 param 和 embed 标签中有关 flash 的一些属性及其属性值. 首先我们需要知道 param 和 embed 标签是单独出现的,而不是成对出现的,下面的代码是一般 flash ...

  3. ssh 断开解决办法

    SSH连接总是隔一段时间没有输入时就断开,解决办法如下: 服务端配置sudo vi /etc/ssh/sshd_configClientAliveInterval 60     #服务端主动向客户端请 ...

  4. Linux C++ 访问子目录以及里面的文件

    #include <iostream> #include <fstream> #include <string> #include <vector> # ...

  5. Pandas 读取文本格式数据

    title 其实书中说的我认为不够全,因为公司里面现在主要用stata和spss,暂时还没有用到sas,excel也很少用 那么读取文件的方式,因为有人已经总结了,我就偷过来算了 对应不同的文件类型有 ...

  6. C艹复合类型(字符串)

    在C艹中有两种字符串形式, 一种是C-风格, 另一种是C艹风格的 初始化: char str[10] = {'a', 'c', 'd', '\0'};char str[20]= “aaa”; stri ...

  7. Spring JDBC SqlUpdate类示例

    org.springframework.jdbc.object.SqlUpdate类提供了表示SQL更新的可重用操作对象. 使用到的 Student 表的结构如下 - CREATE TABLE Stu ...

  8. JAR 归档文件是与平台无关的文件格式

    JAR(Java Archive,Java 归档文件)是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件,可以使用Java软件打开. 为 J2EE 应用程序创建的 JAR 文件是 EAR 文件 ...

  9. (转)TCP连接异常断开检测

    TCP是一种面向连接的协议,连接的建立和断开需要通过收发相应的分节来实现.某些时候,由于网络的故障或是一方主机的突然崩溃而另一方无法检测到,以致始终保持着不存在的连接.下面介绍一种方法来检测这种异常断 ...

  10. Python——getpass

    getpass模块提供了可移植的密码输入,一共包括下面两个函数: 1. getpass.getpass() 2. getpass.getuser() getpass.getpass([prompt[, ...