当前位置:  开发笔记 > 编程语言 > 正文

在.NET中,哪个循环运行得更快,'for'或'foreach'?

如何解决《在.NET中,哪个循环运行得更快,'for'或'foreach'?》经验,为你挑选了20个好方法。

在C#/ VB.NET/.NET中,哪个循环运行得更快,for或者foreach

自从我读了一个for循环工程快于foreach环路很久以前我以为这对所有集合,泛型集合,所有阵列,等真正站在

我搜索谷歌并发现了一些文章,但其中大多数都没有结果(阅读文章的评论)和开放式.

什么是理想的是列出每个场景和相同的最佳解决方案.

例如(只是它应该如何的一个例子):

    迭代1000多个字符串的数组 - for比...更好foreach

    迭代IList(非泛型)字符串 - foreach比...更好for

在网上找到的一些参考文献:

    Emmanuel Schanzer的原创宏伟文章

    CodeProject FOREACH Vs. 对于

    博客 - foreach或不是foreach,这就是问题

    ASP.NET论坛 - NET 1.1 C#forvsforeach

[编辑]

除了可读性方面,我对事实和数据非常感兴趣.有些应用程序的最后一英里性能优化受到挤压很重要.



1> Ian Nelson..:

Patrick Smacchia上个月在博客上写了这个结论,得出以下结论:

List上的for循环比List上的foreach循环便宜2倍多.

在数组上循环比在List上循环便宜约2倍.

因此,使用for循环on array比使用foreach在List上循环便宜5倍(我相信,这就是我们所做的).


+1伟大的文章.但是,永远不要忘记:"过早优化是万恶之源."
@devinb,使用"for"比使用"foreach"更难,因为它添加了代码,另一个变量,需要检查的条件等等.有多少次你在"foreach"循环中看到了一个错误的错误?
阅读博客文章看起来测试是在Debug而不是Release中运行的,因此可能有一个因素.此外,差异仅适用于循环开销.它根本不影响执行循环体的时间,大多数情况下它比移动到列表的下一个元素所花费的时间长得多.这是一个很好的信息,知道你什么时候发现有明显的问题并且你已经明确地测量了你的应用程序的差异并且有明显的改进,但绝对不是删除所有`foreach'的一般建议.
@Hardwareguy,让我看看我是否直截了当.使用`foreach`循环遍历列表比使用`for`循环遍历数组需要花费5倍的时间,并且你称之为无关紧要?这种性能差异可能会对您的应用程序产生影响,而且可能不会,但我不会仅仅将其解雇.
@Hardwareguy:一旦你知道几乎不可接受的速度快,为什么你不应该开始使用它?它不需要额外的时间.
使用`LinkedList`,`foreach`可以比`for循环'更便宜
该链接中的图像被破坏,这是存档的副本http://web.archive.org/web/20140827024150/http://codebetter.com/patricksmacchia/2008/11/19/an-easy-and-efficient-方法对提高净代码演出/
是否值得在此答案上添加限定词;例如,从列表上的“ foreach”切换到数组上的“ for”,(在大多数情况下)不会像暗示的那样将代码的性能提高5倍。如果您所做的只是循环,那是正确的,但是您可以通过完全跳过循环来无限提高性能。如果循环中有代码,则处理仍将花费相同的时间,并且每次迭代仍将处理一次,通常,与之相比,“ for”循环的优势可忽略不计。

2> Jon Skeet..:

首先,反驳德米特里的答案.对于数组,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

接下来,验证Greg关于集合类型的重要性 - 将数组更改List为上面的a,您会得到截然不同的结果.它不仅总体上明显变慢,而且foreach变得比通过索引访问慢得多.话虽如此,我仍然总是喜欢foreach到for循环,它使代码更简单 - 因为可读性几乎总是重要的,而微优化很少.


@JohnB:是的 - 我几乎总是喜欢`List `而不是数组.例外是`char []`和`byte []`,它们通常被视为数据的"块"而不是普通的集合.
鉴于我的测试与其他人的基准测试之间的结果存在奇怪的差异,我认为这应该是博客文章...

3> ctford..:

foreach循环演示比for循环更具体的意图.

使用foreach循环向使用您的代码的任何人演示,您计划对集合中的每个成员执行某些操作,而不管其在集合中的位置.它还表明您没有修改原始集合(如果您尝试,则会抛出异常).

另一个优点foreach是它适用于任何IEnumerable,for只有在有意义的IList地方,每个元素实际上有一个索引.

但是,如果需要使用元素的索引,那么当然应该允许使用for循环.但是如果你不需要使用索引,那么只有一个索引会使代码混乱.

据我所知,没有重大的性能影响.在未来的某个阶段,使用foreach多个内核运行代码可能更容易,但现在不用担心.


ctford:不,不是.编译器肯定无法重新排序`foreach`中的元素.`foreach`与函数式编程完全没有关系.这完全是一种必要的编程范式.你错误地将TPL和PLINQ中发生的事情归结为"foreach".
@BlueTrin:它确实保证了排序(C#规范第8.8.4节正式定义`foreach`相当于`while`循环).我想我知道@ctford是指.任务并行库允许**底层集合**以任意顺序提供元素(通过在可枚举上调用`.AsParallel`).`foreach`在这里没有做任何事情,循环的主体在**单线程**上执行.并行化的唯一事情是生成序列.
Enumerable.Select有一个重载,可以让你获得项目的索引,因此即使需要索引也不要求使用for.请参阅http://msdn.microsoft.com/en-us/library/bb534869.aspx
ForEach便于阅读和保存打字.但成本很重要; 在我创建的文档设计器UI中更改2或3个for循环,从(对于列表中的每个obj)到(对于i = 0到list.count-1)将响应时间从每次编辑的2-3秒缩短到约.在一个小文档上每次编辑5秒,只需循环几百个对象.现在,即使是大型文档,循环所有内容也没有增加.我不知道这是怎么发生的.我所知道的是,替代方案是一个复杂的方案,只能循环一个对象的子集.我会在任何一天做5分钟的改变! - _not_微优化.
@FastAl正常列表的`foreach`和`for`性能之间的差异是迭代数百万项的几分之一秒,所以你的问题肯定与foreach性能没有直接关系,至少不是几百个对象.在您使用的任何列表中听起来像一个破坏的枚举器实现.
@Mehrdad:另外,使用foreach有助于避免将元素处理代码与任何排序概念相结合,从而使其在未来更容易配对.我夸大了自己的观点 - foreach不是地图.

4> Rob Fonseca-..:

任何时候都有关于性能的争论,你只需要编写一个小测试,这样你就可以使用定量结果来支持你的情况.

为了准确,使用StopWatch类并重复几百万次.(没有for循环,这可能很难):

using System.Diagnostics;
//...
Stopwatch sw = new Stopwatch()
sw.Start()
for(int i = 0; i < 1000000;i ++)
{
    //do whatever it is you need to time
}
sw.Stop();
//print out sw.ElapsedMilliseconds

手指越过了这个节目的结果,差异可以忽略不计,你可能只是在最易维护的代码中做任何结果


但你无法比较for和foreach的表现.它们应该在不同的环境中使用.
我同意你迈克尔,你不应该根据性能选择使用哪一个 - 你应该选择最有意义的一个!但如果你的老板说"不要因为它比foreach慢",那么这是说服他差异可以忽略不计的唯一方法

5> Marc Gravell..:

它总是很接近.对于一个数组,有时 for会稍微快一点,但foreach更具表现力,并提供LINQ等.一般来说,坚持使用foreach.

另外,foreach可以在某些情况下进行优化.例如,链接列表可能是索引器可怕的,但它可能很快foreach.实际上,由于LinkedList这个原因,该标准甚至没有提供索引器.


@JohnB - 不瘦; 只是不同.例如,链表中的每个节点都有一个平面数组不需要的附加引用(它也支持`List `).*插入*/*删除*更便宜.

6> Brian Rasmus..:

我的猜测是,在99%的情况下它可能不会很重要,那么为什么你会选择更快而不是最合适的(最容易理解/维护)?


@klew,如果你真的对你的代码进行了分析,你就不必猜测哪个20%需要尽可能快.您可能还会发现需要快速的实际循环次数要低得多.此外,你是否真的说循环行为是你花时间的地方,而不是你在那个循环中实际做的事情?

7> Greg Hewgill..:

两者之间不太可能存在巨大的性能差异.一如既往,面对"哪个更快?" 问题,你应该总是想"我可以衡量这一点."

编写两个在循环体中执行相同操作的循环,对它们执行和计时,并查看速度的差异.用一个几乎空的身体和一个类似于你实际做的循环体来做这件事.也可以使用您正在使用的集合类型来尝试它,因为不同类型的集合可以具有不同的性能特征.



8> T.E.D...:

有很好的理由喜欢 foreach循环遍历for循环.如果你可以使用foreach循环,你的老板是对的.

但是,并非每次迭代都只是逐个按顺序遍历列表.如果他是禁止的,那是错的.

如果我是你,我会做的就是把所有你自然的循环变成递归.那教会了他,这对你来说也是一种很好的心理锻炼.



9> Max Toro..:

Jeffrey Richter在TechEd 2005上:

"多年来,我开始学习C#编译器对我来说基本上是骗子." ......"它涉及许多事情." .."就像你做一个foreach循环......"......"...这是你编写的一小段代码,但C#编译器为了做到这一点而吐出来的是它的现象.它推出了一个在那里尝试/ finally块,在finally块内部,它将你的变量转换为IDisposable接口,如果转换为suceeds,则调用它上面的Dispose方法,在循环内部,它在循环内部重复调用Current属性和MoveNext方法,在封面下创建了对象.很多人都使用foreach,因为它很容易编码,很容易做到.".."foreach在性能方面不是很好,如果你在一个集合上迭代而不是使用square括号表示法,只是做索引,这只是更快,而且它不会在堆上创建任何对象..."

按需网络直播:http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx? EventID = 1032292286&EventCategory = 3& culture = en -US&CountryCode = US



10> Rik..:

这是荒唐的.禁止for循环,性能方面或其他方面没有令人信服的理由.

请参阅Jon Skeet的博客,了解性能基准和其他参数.


更新的链接:http://codeblog.jonskeet.uk/2009/01/29/for-vs-foreach-on-arrays-and-lists/

11> Meta-Knight..:

如果您使用对象集合,foreach则更好,但如果增加数字,则for循环更好.

请注意,在最后一种情况下,您可以执行以下操作:

foreach (int i in Enumerable.Range(1, 10))...

但它肯定表现不佳,与a相比,它的性能实际上更差for.



12> akuhn..:

这应该可以节省你:

public IEnumerator For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

使用:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

为获得更大的胜利,您可以将三名代表作为参数.



13> Alex York..:

当你循环遍历数组,列表等常见结构时,a for和a foreach循环中的速度差异很小,并且LINQ对集合进行查询几乎总是稍微慢一些,尽管写起来更好!正如其他海报所说,追求表现力而不是毫秒的额外表现.

到目前为止还没有说过的是,当foreach编译循环时,编译器会根据迭代的集合对其进行优化.这意味着当你不确定要使用哪个循环时,你应该使用foreach循环 - 它会在编译时为你生成最好的循环.它也更具可读性.

foreach循环的另一个关键优势是,如果您的集合实现发生更改(例如从int array到a List),那么您的foreach循环将不需要任何代码更改:

foreach (int i in myCollection)

无论你的集合是什么类型,上面都是一样的,而在你的for循环中,如果你myCollection从a array变为a ,则不会构建以下内容List:

for (int i = 0; i < myCollection.Length, i++)



14> Andrew Kenna..:

它可能取决于您枚举的集合类型及其索引器的实现.但总的来说,使用foreach可能是一种更好的方法.

此外,它将适用于任何IEnumerable- 不仅仅是索引器的东西.



15> Ken..:

"我可以用任何论据来帮助我说服他使用for循环吗?"

不,如果你的老板微观管理到告诉你使用什么编程语言的水平,你真的没什么可说的.抱歉.



16> NSFW..:

这与大多数"更快"的问题具有相同的两个答案:

1)如果你不测量,你不知道.

2)(因为...)取决于.

这取决于"MoveNext()"方法的成本,相对于"this [int index]"方法的成本,对于您将迭代的IEnumerable的类型(或类型).

"foreach"关键字是一系列操作的简写 - 它在IEnumerable上调用GetEnumerator()一次,每次迭代调用一次MoveNext(),它进行一些类型检查,依此类推.最有可能影响性能测量的是MoveNext()的成本,因为它被调用O(N)次.也许它很便宜,但也许不是.

"for"关键字看起来更可预测,但在大多数"for"循环中,您会发现类似"collection [index]"的内容.这看起来像一个简单的数组索引操作,但它实际上是一个方法调用,其成本完全取决于您迭代的集合的性质.可能它很便宜,但也许不是.

如果集合的底层结构本质上是一个链表,那么MoveNext很便宜,但索引器可能有O(N)成本,这使得"for"循环的真实成本为O(N*N).



17> Reed Copsey..:

每种语言结构都有适当的使用时间和地点.C#语言有四个独立的迭代语句是有原因的- 每个语句都有特定用途,并且具有适当的用途.

我建议与老板坐下来,试着理性地解释为什么for循环有目的.有时for迭代块更清楚地描述算法而不是foreach迭代.如果是这样,则使用它们是合适的.

我还要向你的老板指出 - 性能不是,也不应该是任何实际的问题 - 更多的是以简洁,有意义,可维护的方式表达算法.像这样的微优化完全错过了性能优化,因为任何真正的性能优势都来自算法重新设计和重构,而不是循环重构.

如果经过理性的讨论,仍然存在这种威权观点,那么由你来决定如何进行.就个人而言,我不乐意在一个不鼓励理性思考的环境中工作,并考虑转到不同雇主的另一个职位.但是,我强烈建议在讨厌之前进行讨论 - 可能只是存在一个简单的误解.



18> Brian Rasmus..:

除了这一点之外,是否forforeach实际更快.我严重怀疑选择一个会对你的表现产生重大影响.

优化应用程序的最佳方法是通过分析实际代码.这将确定占用大部分工作/时间的方法.首先优化它们.如果性能仍然不可接受,请重复此过程.

作为一般规则,我建议远离微观优化,因为它们很少会产生任何重大收益.唯一的例外是在优化已识别的热路径时(即,如果您的分析确定了一些高度使用的方法,那么广泛优化这些方法可能是有意义的).


`for`略快于'foreach`.我真的反对这句话.这完全取决于底层的集合.如果链表类为索引器提供了一个整数参数,我希望在它上面使用`for`循环为O(n ^ 2),而`foreach`应该是O(n).

19> Martin Wickm..:

这是你循环中做的影响性能的东西,而不是实际的循环结构(假设你的情况是非平凡的).



20> Or Yaacov..:

您可以在Deep .NET-第1部分迭代中了解它

它涵盖了.NET源代码一直到反汇编的结果(没有第一次初始化)。

例如-具有foreach循环的数组迭代:

和-使用foreach循环列出迭代:

最终结果:

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有