在.NET中,'for'循环和'foreach'循环中哪个运行更快?
在.NET中,'for'循环和'foreach'循环中哪个运行更快?
在C#/VB.NET/.NET中,for
循环和foreach
循环哪个运行更快?\n自从很久以前我读到一篇文章说for
循环比foreach
循环快,我就认为对于所有集合、泛型集合、所有数组等都是成立的。\n我在谷歌上搜索了一些文章,但大部分都没有结论(请阅读文章上的评论)而且是没有明确答案的。\n理想的情况是列出每种情况以及最佳解决方案。\n例如(只是示例):\n
- \n
- 对于遍历超过1000个字符串的数组 -
for
比foreach
更好 - 对于遍历
IList
(非泛型)字符串 -foreach
比for
更好
\n
\n
\n以下是在网络上找到的一些参考资料:\n
- \n
- Emmanuel Schanzer的原始古老文章
- CodeProject的FOREACH Vs. FOR
- 博客 - 使用
foreach
还是for
,这是个问题 - ASP.NET论坛 - .NET 1.1 C#
for
vsforeach
\n
\n
\n
\n
\n[编辑]\n除了可读性之外,我真的对事实和数据很感兴趣。在某些情况下,性能优化的最后一点确实很重要。
在.NET中,'for'循环和'foreach'循环中哪个运行更快的问题的出现是因为两者在使用上有一些区别。'foreach'循环表明了对集合中每个成员都要做一些操作的具体意图,而不管它在集合中的位置。它还表明您不会修改原始集合(如果尝试修改会引发异常)。另外,'foreach'的另一个优点是它适用于任何实现了'IEnumerable'接口的对象,而'for'循环只对实现了'IList'接口的对象有意义,因为每个元素都有一个索引。
然而,如果需要使用元素的索引,那么当然可以使用'for'循环。但是如果不需要使用索引,那么索引只会使代码变得凌乱。
据我所知,这两种循环在性能方面没有明显的影响。在将来的某个阶段,使用'foreach'的代码可能更容易在多个核上运行,但这并不是当前需要担心的事情。
这对于迭代自定义对象列表或数据列表并且在处理数据时不必担心所有索引命名是非常有帮助的。
我无法理解'foreach'如何帮助多线程。我猜你指的是像任务并行库这样的东西,但那并不是'foreach'的奇迹。
编译器在使用'foreach'迭代列表时有自由选择的权利。例如,它可以在一个核上迭代偶数元素,在另一个核上迭代奇数元素。'foreach'更接近函数式编程的风格。
ctford: 不,不是的。编译器肯定不能重新排序'foreach'中的元素。'foreach'与函数式编程没有任何关系。你把发生在TPL和PLINQ中的事情错误地归因于'foreach'。
ctford: 我猜这取决于'foreach'是否保证顺序。如果'foreach'不能保证顺序,未来版本的编译器可以通过使用标记循环体内代码为线程安全的属性来优化使用多核。
在.NET中,'for'循环和'foreach'循环哪个运行速度更快?这个问题的出现是因为有人声称在数组中,C#编译器为'foreach'循环生成的代码与等效的'for'循环几乎相同。为了验证这一点,进行了以下基准测试:
using System; using System.Diagnostics; using System.Linq; class Test { const int Size = 1000000; const int Iterations = 10000; static void Main() { double[] data = new double[Size]; Random rng = new Random(); for (int i=0; i < data.Length; i++) { data[i] = rng.NextDouble(); } double correctSum = data.Sum(); Stopwatch sw = Stopwatch.StartNew(); for (int i=0; i < Iterations; i++) { double sum = 0; for (int j=0; j < data.Length; j++) { sum += data[j]; } if (Math.Abs(sum-correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds); sw = Stopwatch.StartNew(); for (int i=0; i < Iterations; i++) { double sum = 0; foreach (double d in data) { sum += d; } if (Math.Abs(sum-correctSum) > 0.1) { Console.WriteLine("Summation failed"); return; } } sw.Stop(); Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds); } }
测试结果如下:
For loop: 16638 Foreach loop: 16529
从结果可以看出,在这个基准测试中,'for'循环和'foreach'循环的结果基本相同。
接下来,将数组改为List<double>
,再次进行测试,结果截然不同。不仅整体速度明显变慢,而且'foreach'循环比通过索引访问要慢得多。不过,我仍然几乎总是更喜欢使用'foreach'循环,因为代码的可读性几乎总是更重要,而微观优化很少重要。
对于数组和List<T>
,你几乎总是更喜欢使用哪一个?在这种情况下,可读性是否胜过微观优化?
答案是:是的,我几乎总是更喜欢使用List<T>
而不是数组。只有char[]
和byte[]
这两种类型更常被视为数据块而不是普通集合时,才会有例外。
有趣的是,在我的电脑上,对于简单数组,'foreach'循环比'for'循环快了近10%。我猜测这可能是因为即时编译器不需要考虑额外的变量、边界检查等。如果有人能对此进行深入解释,那将非常有趣。
为什么使用List<double>
或其他类型的集合进行'foreach'循环会变慢?在'foreach'循环之前将列表转换为数组是否有用,还是只是浪费内存?同样的情况是否适用于IEnumerable<double>
?
答案是:我不记得当时是否研究过这个问题(请记住这是13年多以前的事情了),但我不会对此感到意外,因为事情在此期间可能发生了很大的变化。故事的寓意是:始终进行测量。
在.NET中,'for'和'foreach'循环哪个运行更快的问题出现的原因是因为在一个博客中提到了这个问题,并给出了一些结论。这些结论包括:对于List来说,使用for循环比使用foreach循环要快2倍多;对于数组来说,使用for循环比使用foreach循环要快2倍左右;因此,使用for循环来遍历数组比使用foreach循环来遍历List要快5倍。
然而,我们不能忘记一句话:"过早优化是万恶之源"。虽然我们知道for循环几乎是看不出快多少的,但为什么我们不应该通常开始使用它呢?这不需要额外的时间。
使用for循环比使用foreach循环更难,因为它需要添加代码、另一个变量、需要检查的条件等等。你有多少次在foreach循环中看到过一个偏移错误呢?
让我来看看我是否理解正确。使用foreach循环遍历List要比使用for循环遍历数组要慢5倍,你认为这是微不足道的吗?这种性能差异可能对你的应用程序有影响,也可能没有,但我不会轻易地忽视它。
阅读博客文章后,我发现这些测试是在Debug模式下运行的,而不是Release模式,所以这可能有一定的影响。此外,这种差异只是在循环开销上,不会影响执行循环体的时间,而在大多数情况下,执行循环体的时间要比移动到列表的下一个元素的时间长得多。当你确定存在问题并测量了你的应用程序中的差异,并且有明显的改进时,这是一条有用的信息,但绝对不是删除所有的foreach循环的一般建议。
使用LinkedList时,foreach循环可能比for循环更便宜。
那个链接中的图片已经损坏了,这是存档的副本。
我已经使用Stopwatch在发布模式下检查了当前的结果。结果与写这篇文章时已经发生了变化。1. List < int > 循环几乎比foreach循环快7倍。进行了100,000,000^2次迭代。优化了计数的for循环是最快的,但与没有优化的示例几乎没有区别(未优化的for循环:326;优化了计数的for循环:296;foreach循环:2356)。2. 但是,更有趣的是。在某些情况下,对于int[]数组,foreach循环比for循环略快(未优化的for循环:294;优化了计数的for循环:294;foreach循环:267,更少!)。也是10^8^2次操作。
我知道你是指包括索引查找,但是一个for (n = l.First; n != null; n = n.Next)
循环的性能大约是在foreach循环和相应的基于数组的for循环之间的。
你能用更清楚的方式替换"cheaper"吗?这样会更清晰。
在jacksondunstan的文章中,没有进行ForEach - Assignment的操作。我已经改变了代码并按照你所说的执行了,结果没有改变......谢谢 :-0)
这个答案是否值得添加一个限定词?也就是说,从在List上使用foreach到在数组上使用for并不能(在大多数情况下)将代码的性能提高5倍,如所示。如果你只是循环,那么是对的,但是你可以通过跳过循环来无限提高性能。如果循环体内有代码,那么处理它的时间仍然是一样长的,并且通常每次迭代都会处理一次,这使得for循环的好处相对较小。
如果这些数字是准确的,那么这是一个编译器的问题,可以在编译器级别解决。我认为易用性更重要。如果不是在代码中的一个极热的路径上,没有人应该关心。
想说一句话,当你在移动设备上工作时,当你发现你的堆受到限制,并且由于内存碎片而崩溃时,请检查你有多少个foreach循环。foreach循环分配内存并引起垃圾回收,所以这里不是过早优化的问题。
因为在几个Azure函数中进行了大量迭代的优化(50万-150万个项目,多次遍历和查找相同的列表),使用for循环在所有情况下都提供了更好的性能。甚至将赋值给一个本地变量(var item = list[i];)也会立即提高性能。还有其他一些技巧用于所需的性能提升(并行,哈希集,查找-基于特定代码中的非常特定的需求的组合),但根据我的经验,for循环更快。毫无疑问。
只是一个值得注意的事情,来自Stephen Cleary的《C#并发烹饪书》中提到:“对于ImmutableList
这个回答在14年前可能是正确的,但我认为差距已经大大缩小了。对于列表来说,我得到了30%的差异,对于数组来说,我得到了50%的差异。