这篇文章是引用芽儿博客
for和foreach 的效率问题是个老问题了,从网上看到的是众说纷纭,有说for效率高的也有说foreach效率高的,还有说测试方法有问题的;鉴于此,我就自己做了个试验证明一下,然后探究一下可能的原因。
先看测试结果:
再看测试代码(如果大家觉得我的测试有问题,请提出来呀):
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace ForVSForEach
{
class Program
{
const int ARRAY_LENGTH = 9000000;
static void Main(string[] args)
{
ForVSForEach(8);
ForVSForEach(new Person());
Console.Read();
}
static void ForVSForEach<T>(T type) where T:new()
{
T[] array = new T[ARRAY_LENGTH];
for (int i = 0; i < array.Length; i++)
{
array[i] = new T();
}
Stopwatch watch = new System.Diagnostics.Stopwatch();
T tempFor = default(T);
watch.Start();
for (int i = 0; i < array.Length; i++)
{
tempFor = array[i];
}
watch.Stop();
long forTicks = watch.ElapsedTicks;
T tempForeach = default(T);
watch.Reset();
watch.Start();
foreach (T i in array)
{
tempForeach = i;
}
watch.Stop();
long forEachTicks = watch.ElapsedTicks;
//Console.WriteLine(tempFor);
Console.WriteLine("使用的类型:{0},循环次数:{1}",typeof(T),ARRAY_LENGTH);
Console.WriteLine("for use time {0}", forTicks);
Console.WriteLine("foreach use time {0}", forEachTicks);
}
}
class Person
{
public Person() { }
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
}
原因分析:
为了使一个类实例可以被foreach 需要继承 IEnumerable 接口,而此接口只有一个方法,返回一个IEnumerator的接口实例,这就说明foreach是通过操纵IEnumerator的方法来实现的。我们再看IEnumerator的两个方法和一个属性:
属性:object Current {get;}
方法:bool MoveNext()
void Reset()
我们可以推断一下foreach的实现,下面是伪代码:(下面的假设是错误的)
Object foreachObj = null ;
enumerator.Reset(); // 有可能会在此处执行一下Reset以保证从集合的第一个元素开始foreach。
foreachStart :
if (enumerator.MoveNext())
{
foreachObj = enumerator.Current;
{
//this area is the foreach block
}
goto foreachStart;
}
foreachEnd:
让我们再分析一下for(int i=0;i<array.length;i++)的可能执行过程:
forStart:
if(i< array.length)
{
{
//this area is the for block
}
goto forStart;
}
forEnd:
很显然for的执行过程中少了几个方法的执行,而且要少一些额外的步骤,这是不是for效率比foreach稍高一筹的原因呢?由于以上推断纯属个人推断,所以还不敢下结论,请大家帮忙找一下理论根据。
最后:
虽然说for比foreach效率稍微高一点,但是foreach的更优雅一点,另外for除了效率之外也有一个优点就是我们可以在执行for的过程中更新,删除集合的元素值,而在foreach中这是不允许的。
如果既可以使用for也可以使用foreach的时候,我们可以使用foreach使代码优雅一点,除非这段代码需要特别注意性能。
请大家注意:
以上的结论和推断都是错误的,上面的那个dos窗口图片中的执行结果,是在调试模式下面的执行结果,调试模式下没有性能优化,和实际结果相差很远,实际的编译成release版本的执行结果如下:
大家可以看到经过优化之后,是
理论根据IL编译代码(来自一位老外的blog http://blogs.msdn.com/kevin_ransom/archive/2004/04/19/116072.aspx ):
foreach 的性能更高一点。
static void One() | static void Two() |
.method private hidebysig static void One() cil managed | .method private hidebysig static void Two() cil managed |
IL_0000: ldc.i4 0x2710 | IL_0000: ldc.i4 0x2710 |
IL_0011: ldloc.2 | IL_000f: ldloc.0 |
IL_0025: ret |
|
大家可以参考下面的三篇文章:
http://blogs.msdn.com/kevin_ransom/archive/2004/04/19/116072.aspx
http://blogs.msdn.com/brada/archive/2004/04/29/123105.aspx
http://www.cnblogs.com/WuCountry/archive/2007/02/27/658710.html 另外,我补充一下foreach需要实现哪个接口的什么方法:
只要实现了IEnumerable接口就可以被foreach了,IEnumerator接口是不需要实现的,只要这个类能够通过GetEnumerator方法返回一个IEnumerator就可以了。
IEnumerable接口只有一个方法IEnumerator GetEnumerator(),最简单的例子类如下:
{
private ArrayList _arrayList;
public IEnumeratorClass(ArrayList list)
{
_arrayList = list;
}
IEnumerable 成员#region IEnumerable 成员
public IEnumerator GetEnumerator()
{
return _arrayList.GetEnumerator();
}
#endregion
}