关于性能:C#中IEnumerable类的foreach和for循环之间的区别

关于性能:C#中IEnumerable类的foreach和for循环之间的区别

Difference between foreach and for loops over an IEnumerable class in C#

我被告知以下代码块之间存在性能差异。

1
2
3
4
foreach (Entity e in entityList)
{
 ....
}

1
2
3
4
5
for (int i=0; i<entityList.Count; i++)
{
   Entity e = (Entity)entityList[i];
   ...
}

在哪里?

1
List<Entity> entityList;

我不是clr所期望的,但从我所能知道的来看,它们应该归结为基本上相同的代码。有没有人有确凿的证据(见鬼,我会拿包装好的泥土)来证明?


foreach创建枚举器的实例(从getEnumerator返回),该枚举器在foreach循环的整个过程中也保持状态。然后它反复调用枚举器上的next()对象,并为它返回的每个对象运行代码。

它们不会以任何方式归结为相同的代码,实际上,如果编写自己的枚举器,您会看到这一点。


这是一篇很好的文章,展示了两个循环之间的IL差异。

foreach在技术上速度较慢,但更易于使用和阅读。除非性能至关重要,否则我更喜欢foreach循环而不是for循环。


foreach示例大致对应于以下代码:

1
2
3
4
5
6
using(IEnumerator<Entity> e = entityList.GetEnumerator()) {
    while(e.MoveNext()) {
        Entity entity = e.Current;
        ...
    }
}

这里有两个费用,一个普通的for循环不需要支付:

  • EntityList.GetEnumerator()分配枚举器对象的成本。
  • 列表中每个元素的两个虚拟方法调用(moveNext和current)的开销。

  • 这里漏了一点:列表有一个Count属性,它在内部跟踪其中有多少元素。

    IEnumerable没有。

    如果您编程到接口IEnumerable并使用Count扩展方法,它将枚举以计数元素。

    但这是一个无意义的点,因为在IEnumerable中不能按索引引用项。

    因此,如果您想锁定到列表和数组中,您可以获得较小的性能提升。

    如果你想灵活使用foreach和程序到ienumerable。(允许使用LINQ和/或产量返回)。


    在分配方面,最好看一下这个blogpost。它精确地显示了在什么情况下在堆上分配枚举器。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    For Loop
    for loop is used to perform the opreration n times
    for(int i=0;i<n;i++)
    {
    l=i;
    }
    foreach loop

    int[] i={1,2,3,4,5,6}
    foreach loop is used to perform each operation value/object in IEnumarable
    foreach(var k in i)
    {
    l=k;
    }


    我认为一种可能的情况是,如果可枚举类型的大小和循环条件为常量,则可能获得性能提升;例如:

    1
    2
    3
    4
    5
    6
    const int ArraySize = 10;
    int[] values = new int[ArraySize];

    //...

    for (int i = 0; i

    在这种情况下,根据循环体的复杂性,编译器可能能够用内联调用替换循环。我不知道.NET编译器是否会这样做,如果可枚举类型的大小是动态的,那么它的实用程序是有限的。

    foreach可能表现得更好的一种情况是使用数据结构,如链表,其中随机访问意味着遍历链表;foreach使用的枚举器可能一次迭代一个项目,使每个访问O(1)和全循环O(n),但调用索引器意味着从头部开始并在右索引;O(n)每个循环代表O(n^2)。

    就我个人而言,我通常不担心它,在我需要所有项目的任何时候使用foreach,也不关心项目的索引。如果我没有处理所有项目,或者我真的需要知道索引,我使用for。唯一一次我能看到它是一个大问题是像链表这样的结构。


    推荐阅读

      linux循环复制命令?

      linux循环复制命令?,系统,文件,命令,目录,地址,源文件,文件夹,目标,文件名,

      linux解压命令的区别?

      linux解压命令的区别?,系统,工具,电脑,命令,文件,资料,平台,档案,名称,文件

      linux命令和程序区别?

      linux命令和程序区别?,系统,标准,环境,情况,控制权,服务,软件,信息,命令,文

      linux命令中和区别?

      linux命令中和区别?,系统,认证,电脑,网址,标准,工作,工具,位置,命令,文件,了

      linux中和命令的区别?

      linux中和命令的区别?,系统,网络,软件,标准,命令,控制权,基础,平台,代码,投

      linux命令行写循环?

      linux命令行写循环?,工作,系统,地址,命令,情况,定期,基础,连续,信息,文件,Lin

      linux循环命令脚本?

      linux循环命令脚本?,代码,系统,增长,工具,官网,项目,流程,数据,数字,底部,lin

      linux跳出死循环命令?

      linux跳出死循环命令?,系统,地址,数字,代码,官方网站,网络,工作,工具,信息,

      linux性能测试命令?

      linux性能测试命令?,数据,系统,工具,标准,设备,地址,情况,基础,网络,环境,如

      linux循环语句命令?

      linux循环语句命令?,地方,增长,数字,语句,流程,名称,工具,代码,数据,条件,Lin

      dolinux循环命令?

      dolinux循环命令?,系统,工具,时间,信息,增长,代码,对比,数字,官网,定期,如何

      linux关机命令区别?

      linux关机命令区别?,系统,工作,命令,信息,用户,进程,方式,方法,终端,区别,lin

      linux命令3d性能?

      linux命令3d性能?,系统,工具,实时,百分比,信息,分析,软件,情况,网站,建设,Lin

      linux性能管理命令?

      linux性能管理命令?,工具,系统,信息,状态,网络,情况,工作,时间,短信,平均,lin

      linux性能调参命令?

      linux性能调参命令?,工具,工作,信息,网络,分析,系统,地址,实时,管理,状态,在l

      linux压缩命令的区别?

      linux压缩命令的区别?,系统,命令,文件,名称,定期,一致,设备,目录,文件夹,后

      linux内外部命令区别?

      linux内外部命令区别?,系统,软件,盘中,命令,基础,外部,内部,内存,口令,用户,L

      linux内部命令区别?

      linux内部命令区别?,系统,软件,盘中,工作,命令,时间,信息,外部,内存,内部,Lin

      linux性能找不打命令?

      linux性能找不打命令?,系统,实时,软件,名字,分析,信息,情况,工具,电脑,时间,l

      linux版本间命令区别?

      linux版本间命令区别?,软件,系统,通用,服务,网络,名字,命令,骗局,技术,发行,