C#中for和foreach循环的性能
2011-07-24 12:51
267 查看
大家先来看看如下三个循环:
int[] foo = new int[100];
1,foreach (int i in foo)
Console.WriteLine(i.ToString());
复制代码2,for(int index=0;index<foo.Length;index++)
Console.WriteLine(foo[index].ToString());
复制代码3,int len=foo.Length;
for(int index=0;index<len;index++)
Console.WriteLine(foo[index].ToString());
复制代码这三个循环是我在看《Effective C# 中文版(改善程序的50种方法)PDF下载》中看到的,发现书中说第三个循环和如下代码等效,经过使用ILDasm.exe工具查看IL代码发现这个说法并不正确:int len=foo.Length;
for(int index=0;index<len;index++)
{
if(index<foo.Length)
Console.WriteLine(foo[index].ToString());
else
throw new IndexOutOfRangeException();
}
复制代码书中的看法是数组的边界测试会被执行两次(编译器生成的代码一次,JIT编译阶段还要执行一次检查),但是的确没有在IL代码中发现C#的编译器生成类似的逻辑,所以这个说法有问题!
一般C++转过来的程序员都很喜欢这样写循环,认为这样就不会每一次循环都计算一次Length属性的值了,可以带来性能上的提升!经查看IL代码,实际情况也就是如此!
但是,这样写会带来另外的问题,那就是破坏了JIT对代码的进行的优化,这样的写法在每一次循环中都要做数组的边界检查,这样也带来了性能上的损失,而且这个损失要比每次计算Length要大,如果我们按第二种写法,JIT只在第一次循环之前检查一次数组界限(JIT这种优化只针对f循环中访问一维0基数组,并且索引是0和Length之间的元素)
看来JIT不喜欢我们这样帮助他优化代码,这样反而破坏了JIT本身的优化!
我们再来看看第一种写法和第二种写法,通过查看IL代码,他们生成的代码比较类似,差别是使用foreach循环是把数组元素放到i变量里!
C#编译器对第一种写法(使用foreach循环)针对数组做了特殊的处理,并没有像其他集合那样在内部使用迭代器,这里如果使用迭代器的话会导致装箱和拆箱操作,这样会带来性能上的损失!看来C#编译器总是可以为foreach生成很高效率的代码,而且可以带来很多其他的好处,例如简化代码的编写,或是将来把foo变成其他集合 而foreach循环不必修改(使用for循环必须修改代码),操作数强制类型转换等。
int[] foo = new int[100];
1,foreach (int i in foo)
Console.WriteLine(i.ToString());
复制代码2,for(int index=0;index<foo.Length;index++)
Console.WriteLine(foo[index].ToString());
复制代码3,int len=foo.Length;
for(int index=0;index<len;index++)
Console.WriteLine(foo[index].ToString());
复制代码这三个循环是我在看《Effective C# 中文版(改善程序的50种方法)PDF下载》中看到的,发现书中说第三个循环和如下代码等效,经过使用ILDasm.exe工具查看IL代码发现这个说法并不正确:int len=foo.Length;
for(int index=0;index<len;index++)
{
if(index<foo.Length)
Console.WriteLine(foo[index].ToString());
else
throw new IndexOutOfRangeException();
}
复制代码书中的看法是数组的边界测试会被执行两次(编译器生成的代码一次,JIT编译阶段还要执行一次检查),但是的确没有在IL代码中发现C#的编译器生成类似的逻辑,所以这个说法有问题!
一般C++转过来的程序员都很喜欢这样写循环,认为这样就不会每一次循环都计算一次Length属性的值了,可以带来性能上的提升!经查看IL代码,实际情况也就是如此!
但是,这样写会带来另外的问题,那就是破坏了JIT对代码的进行的优化,这样的写法在每一次循环中都要做数组的边界检查,这样也带来了性能上的损失,而且这个损失要比每次计算Length要大,如果我们按第二种写法,JIT只在第一次循环之前检查一次数组界限(JIT这种优化只针对f循环中访问一维0基数组,并且索引是0和Length之间的元素)
看来JIT不喜欢我们这样帮助他优化代码,这样反而破坏了JIT本身的优化!
我们再来看看第一种写法和第二种写法,通过查看IL代码,他们生成的代码比较类似,差别是使用foreach循环是把数组元素放到i变量里!
C#编译器对第一种写法(使用foreach循环)针对数组做了特殊的处理,并没有像其他集合那样在内部使用迭代器,这里如果使用迭代器的话会导致装箱和拆箱操作,这样会带来性能上的损失!看来C#编译器总是可以为foreach生成很高效率的代码,而且可以带来很多其他的好处,例如简化代码的编写,或是将来把foo变成其他集合 而foreach循环不必修改(使用for循环必须修改代码),操作数强制类型转换等。
相关文章推荐
- C#中for和foreach循环的性能
- C#中for和foreach循环的性能
- 对比C#中for和foreach循环的性能
- 对比C#中for和foreach循环的性能
- C#访问Xml 关于Foreach 和For循环
- C# for和foreach的性能问题
- C# 中 for和foreach 性能比较
- C#中循环语句:while、for、foreach的使用
- Java for循环和foreach循环的性能比较
- java for/foreach/while 3种循环性能比较
- C# 中 for和foreach 性能比较,提高编程性能 (转贴)
- C# for和foreach循环
- C#中foreach,for,while,Do-While循环
- C# 中 for和foreach 性能比较,提高编程性能
- C#中foreach,for,while,Do-While循环
- C#中foreach,for,while,Do-While循环对比
- java基础复习四:for与foreach的循环性能比较
- C# for VS foreach 性能对比
- C# 中 for和foreach 性能比较,提高编程性能
- C# 中 for和foreach 性能比较,提高编程性能