2008-09-04 107 views
12

我被告知在下面的代码块之间存在性能差异。C#中IEnumerable类的foreach和for循环之间的区别

foreach (Entity e in entityList) 
{ 
.... 
} 

for (int i=0; i<entityList.Count; i++) 
{ 
    Entity e = (Entity)entityList[i]; 
    ... 
} 

其中

List<Entity> entityList; 

我也不指望CLR但我可以告诉他们应该归结为基本相同的代码。有没有人有这样或那样的具体(嘿,我会采取包装污垢)证据?

回答

8

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

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

9

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

Foreach在技术上比较慢,但使用起来更容易,也更易于阅读。除非性能至关重要,否则我更喜欢for循环的foreach循环。

0

我认为一种可能的情况,其中可能得到的性能增益是如果可枚举类型的大小和循环条件是一个常数;例如:

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我需要所有物品并且不关心物品的索引。如果我没有使用所有的项目,或者我真的需要知道索引,我使用。我唯一能看到它是一个大问题的是像链表这样的结构。

6

在foreach样品大致相当于此代码:

using(IEnumerator<Entity> e = entityList.GetEnumerator()) { 
    while(e.MoveNext()) { 
     Entity entity = e.Current; 
     ... 
    } 
} 

这里有两个成本,一个普通的for循环不必支付:

  1. 通过分配枚举器对象的成本entityList.GetEnumerator()。
  2. 列表中每个元素的两个虚方法调用(MoveNext和Current)的代价。
1

就分配而言,最好是看看this blogpost。它完全显示了在什么情况下枚举器在堆上分配。

3

有一点在这里错过了: 一个List有一个Count属性,它在内部跟踪其中有多少个元素。

IEnumerable不。

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

尽管由于在IEnumerable中没有办法引用项目索引。

所以,如果你想锁定列表和数组,你可以获得小的性能提升。

如果您希望flexability使用foreach并编程为IEnumerable。 (允许使用linq和/或收益回报)。

0
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; 
} 
相关问题