关于c#:在.NET中,哪个循环运行得更快,’for’或’foreach’?

In .NET, which loop runs faster, 'for' or 'foreach'?

在VB.NET # / C / .NET,这回路运行时,forforeach

自从我读过一个for环A环foreach作品更快比a长时间前,它只是为我所有的方式通过所有集合,集合,数组等。

我有一个谷歌scoured招领,但大多数人是inconclusive(读评论的文章)和开放的结束。

什么是理想的情况下,有一个最佳的解决方案和列相同。

例如,只是应该如何为例):

  • 迭代阵列1000 +的研究for是更好的比foreach字符串
  • 的迭代过IList(非通用的字符串foreach)是更好的比for
  • 一些人发现Web上的同一个:

  • 原创文章由Emmanuel schanzer大老
  • codeproject上foreach和for
  • 博客是一foreachforeach或不,这是一个问题
  • ASP.NET论坛网# 1.1 C foreachforvs
  • [编辑]

    除了从readability方面它,我真的有兴趣的事实和数字。有应用程序在性能优化的压缩负荷英里做物。


    Patrick Smacchia在上个月的博客中提到了这个问题,得出了以下结论:

    • for loops on List are a bit more than 2 times cheaper than foreach
      loops on List.
    • Looping on array is around 2 times cheaper than looping on List.
    • As a consequence, looping on array using for is 5 times cheaper
      than looping on List using foreach
      (which I believe, is what we all do).


    for循环相比,foreach循环显示出更具体的意图。

    使用foreach循环向使用代码的任何人证明,无论集合在集合中的位置如何,您都计划对集合的每个成员执行某些操作。它还显示您没有修改原始集合(如果您尝试这样做,会抛出一个异常)。

    foreach的另一个优点是它适用于任何IEnumerable,其中for只适用于IList,其中每个元素实际上都有一个索引。

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

    据我所知,没有显著的性能影响。在将来的某个阶段,使用foreach在多个内核上运行可能更容易调整代码,但现在这不是需要担心的事情。


    首先,对德米特里的回答提出反诉。对于数组,C编译器为foreach发出的代码基本上与等效的for循环相同。这就解释了为什么这个基准测试的结果基本相同:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    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);
        }
    }

    结果:

    1
    2
    For loop: 16638
    Foreach loop: 16529

    接下来,验证greg关于集合类型的观点是否重要-在上面将数组更改为List,您会得到完全不同的结果。它不仅在一般情况下明显较慢,而且foreach的访问速度也明显慢于索引。尽管如此,我仍然几乎总是喜欢foreach而不是for循环,因为它使代码更简单,因为可读性几乎总是很重要的,而微优化很少。


    每当有关于性能的争论时,您只需要编写一个小测试,这样您就可以使用定量结果来支持您的案例。

    为了准确起见,使用秒表类并重复上百万次。(没有for循环可能很难做到这一点):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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更具表现力,并提供linq等。一般来说,坚持foreach的方式。

    此外,在某些情况下,foreach可能会得到优化。例如,一个链表对于索引器来说可能很糟糕,但是对于foreach来说可能很快。实际上,标准的LinkedList甚至没有为此提供索引器。


    我的猜测是,这在99%的案例中可能并不重要,所以为什么你会选择更快的而不是最合适的(就像最容易理解/维护的那样)?


    两者之间不太可能有巨大的性能差异。像往常一样,当面对"哪个更快?"问题是,你应该一直认为"我可以测量这个"。

    在循环体中编写两个执行相同操作的循环,执行它们并对其计时,然后查看速度的差异。这样做既有一个几乎是空的身体,也有一个类似于你实际将要做的循环身体。还可以尝试使用正在使用的集合类型,因为不同类型的集合可能具有不同的性能特征。


    有很好的理由比for循环更喜欢foreach循环。如果你可以使用一个foreach循环,你的老板是对的,你应该这样做。

    然而,并不是每个迭代都只是按顺序逐个地遍历一个列表。如果他是禁止的,是的,那是错误的。

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


    Jeffrey Richter,2005年技术教育:

    "I have come to learn over the years the C# compiler is basically a liar to me." .."It lies about many things." .."Like when you do a foreach loop..." .."...that is one little line of code that you write, but what the C# compiler spits out in order to do that it's phenomenal. It puts out a try/finally block in there, inside the finally block it casts your variable to an IDisposable interface, and if the cast suceeds it calls the Dispose method on it, inside the loop it calls the Current property and the MoveNext method repeatedly inside the loop, objects are being created underneath the covers. A lot of people use foreach because it's very easy coding, very easy to do.." .."foreach is not very good in terms of performance, if you iterated over a collection instead by using square bracket notation, just doing index, that's just much faster, and it doesn't create any objects on the heap..."

    点播网络广播:http://msevents.microsoft.com/cui/webcastEventDetails.aspx?eventId=1032292286&eventCategory=3&culture=en美国&countrycode=us


    这太荒谬了。没有令人信服的理由禁止for循环、性能方面的循环或其他循环。

    有关性能基准和其他参数,请参阅JonSkeet的博客。


    在处理对象集合的情况下,foreach更好,但如果增加一个数字,则for循环更好。

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

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

    但它确实没有表现得更好,实际上它的性能比for差。


    这样可以节省您:

    1
    2
    3
    4
    5
    6
    7
    public IEnumerator<int> For(int start, int end, int step) {
        int n = start;
        while (n <= end) {
            yield n;
            n += step;
        }
    }

    用途:

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

    为了获得更大的胜利,您可以将三个代表作为参数。


    当您循环访问诸如数组、列表等常见结构,并且对集合执行LINQ查询时,forforeach循环中的速度差异非常小,尽管编写起来更好,但几乎总是稍微慢一点!正如其他海报所说,追求表现力而不是一毫秒的额外表现。

    到目前为止还没有说的是,当编译foreach循环时,编译器会根据循环的集合对其进行优化。这意味着,当您不确定要使用哪个循环时,应该使用foreach循环—它将在编译时为您生成最佳循环。它的可读性也更高。

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

    1
    foreach (int i in myCollection)

    无论您的收藏是什么类型,上述内容都是相同的,而在您的for循环中,如果您将myCollectionarray更改为List则不会构建以下内容:

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

    "有没有什么可以帮助我说服他使用for循环的论点?"

    不,如果你的老板微观管理到告诉你要使用什么编程语言结构的程度,你真的无话可说。对不起的。


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

    1)如果你不测量,你就不知道。

    (因为…)这要看情况而定。

    它取决于"moveNext()"方法的开销,相对于"this[int index]"方法的开销,对于要迭代的IEnumerable类型(或类型)。

    foreach关键字是一系列操作的简写,它对ienumerable调用一次getEnumerator(),每次迭代调用一次moveNext(),执行一些类型检查,等等。最有可能影响性能度量的是moveNext()的成本,因为它被调用了O(n)次。也许它很便宜,但也许不是。

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

    如果集合的底层结构本质上是一个链表,moveNext是非常便宜的,但是索引器可能有O(n)成本,这使得"for"循环的真正成本为O(n*n)。


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

    此外,它还可以与任何IEnumerable一起使用,而不仅仅是与索引器一起使用。


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

    我建议你和你的老板坐下来,试着理性地解释为什么一个for循环有目的。有时,for迭代块比foreach迭代更清楚地描述算法。如果这是真的,那么使用它们是合适的。

    我也会向你的老板指出——绩效不是,也不应该是任何实际问题——它更像是一个用简洁、有意义、可维护的方式表达算法的问题。像这样的微观优化完全错过了性能优化的要点,因为任何真正的性能优势都将来自算法重新设计和重构,而不是循环重构。

    如果,经过理性的讨论,仍然有这种独裁的观点,那就取决于你如何继续下去。就我个人而言,我不愿意在一个不鼓励理性思维的环境中工作,并考虑在另一个雇主的领导下换一个职位。不过,我强烈建议在心烦意乱之前进行讨论——可能只是存在一个简单的误解。


    它是您在循环中所做的,会影响性能,而不是实际的循环构造(假设您的情况非常重要)。


    for是否比foreach快,真的不是重点。我严重怀疑,选择一个会对你的表现产生重大影响。

    优化应用程序的最佳方法是通过分析实际代码。这将精确指出占大多数工作/时间的方法。首先优化这些。如果性能仍然不合格,重复该步骤。

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


    两者的运行方式几乎完全相同。编写一些代码来同时使用这两种方法,然后向他显示IL。它应该显示可比较的计算,这意味着性能没有差异。


    您可以在deep.net中阅读它-第1部分迭代

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

    例如-使用foreach循环的数组迭代:enter image description here

    和-列出foreach循环的迭代:enter image description here

    最终结果是:enter image description here

    enter image description here


    Jeffrey Richter在最近的一个播客中谈到for和foreach的性能差异:http://pixel8.infrasogistics.com/show/everything.aspx插曲:9317


    我发现foreach循环迭代List更快。请看下面我的测试结果。在下面的代码中,我使用forforeach循环分别迭代大小为100、10000和100000的array来测量时间。

    enter image description here

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    private static void MeasureTime()
        {
            var array = new int[10000];
            var list = array.ToList();
            Console.WriteLine("Array size: {0}", array.Length);

            Console.WriteLine("Array For loop ......");
            var stopWatch = Stopwatch.StartNew();
            for (int i = 0; i < array.Length; i++)
            {
                Thread.Sleep(1);
            }
            stopWatch.Stop();
            Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds);

            Console.WriteLine("");
            Console.WriteLine("Array Foreach loop ......");
            var stopWatch1 = Stopwatch.StartNew();
            foreach (var item in array)
            {
                Thread.Sleep(1);
            }
            stopWatch1.Stop();
            Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds);

            Console.WriteLine("");
            Console.WriteLine("List For loop ......");
            var stopWatch2 = Stopwatch.StartNew();
            for (int i = 0; i < list.Count; i++)
            {
                Thread.Sleep(1);
            }
            stopWatch2.Stop();
            Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds);

            Console.WriteLine("");
            Console.WriteLine("List Foreach loop ......");
            var stopWatch3 = Stopwatch.StartNew();
            foreach (var item in list)
            {
                Thread.Sleep(1);
            }
            stopWatch3.Stop();
            Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds);
        }

    更新的

    在@jgauffin建议之后,我使用了@johnskeet代码,发现带EDOCX1[7]的EDOCX1[0]循环比后面的快,

    • 带数组的foreach循环。
    • for循环与列表。
    • 带列表的foreach循环。

    查看我的测试结果和下面的代码,

    enter image description here

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    private static void MeasureNewTime()
        {
            var data = new double[Size];
            var rng = new Random();
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = rng.NextDouble();
            }
            Console.WriteLine("Lenght of array: {0}", data.Length);
            Console.WriteLine("No. of iteration: {0}", Iterations);
            Console.WriteLine("");
            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 with Array: {0}", sw.ElapsedMilliseconds);

            sw = Stopwatch.StartNew();
            for (var 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 with Array: {0}", sw.ElapsedMilliseconds);
            Console.WriteLine("");

            var dataList = data.ToList();
            sw = Stopwatch.StartNew();
            for (int i = 0; i < Iterations; i++)
            {
                double sum = 0;
                for (int j = 0; j < dataList.Count; j++)
                {
                    sum += data[j];
                }
                if (Math.Abs(sum - correctSum) > 0.1)
                {
                    Console.WriteLine("Summation failed");
                    return;
                }
            }
            sw.Stop();
            Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds);

            sw = Stopwatch.StartNew();
            for (int i = 0; i < Iterations; i++)
            {
                double sum = 0;
                foreach (double d in dataList)
                {
                    sum += d;
                }
                if (Math.Abs(sum - correctSum) > 0.1)
                {
                    Console.WriteLine("Summation failed");
                    return;
                }
            }
            sw.Stop();
            Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds);
        }


    真的用他的头拧上螺丝,然后去检查一下。改为在关闭前:

    mylist.foreach(c=>console.writeline(c.toString());

    英雄联盟


    因为有更简单的逻辑来实现,所以它比foreach更快。


    除非您处于特定的速度优化过程中,否则我会说使用任何一种方法都可以生成最容易读取和维护的代码。

    如果已经设置了迭代器,就像其中一个集合类那样,那么foreach是一个很好的简单选项。如果它是一个你正在迭代的整数范围,那么for可能更干净。


    在大多数情况下,没有什么区别。

    通常,当没有显式的数字索引时,必须始终使用foreach,而当实际上没有可迭代的集合(例如,在上三角形中迭代二维数组网格)时,必须始终使用foreach。有些情况下你可以选择。

    有人可能会说,如果代码中开始出现幻数,那么for循环的维护可能会稍微困难一些。对于不能使用for循环而必须构建集合或使用lambda来构建子集合而不是仅仅因为for循环已被禁止,您应该感到恼火。


    我不希望有人发现两者之间的"巨大"性能差异。

    我想答案取决于您试图访问的集合是具有更快的索引器访问实现还是更快的IEnumerator访问实现。由于IEnumerator经常使用索引器,并且只保存当前索引位置的副本,因此我希望枚举器访问速度至少与直接索引访问一样慢或更慢,但不会太快。

    当然,这个答案不能解释编译器可能实现的任何优化。


    请记住,for循环和foreach循环并不总是等效的。如果列表更改,则列表枚举器将引发异常,但对于正常的for循环,您不会总是收到该警告。如果列表在错误的时间更改,您甚至可能会得到不同的异常。


    完全禁止使用for循环似乎有点奇怪。

    这里有一篇有趣的文章,介绍了两个循环之间的很多性能差异。

    我个人认为foreach对于循环来说更具可读性,但是如果for循环更合适的话,您应该使用最适合手头工作的代码,而不必编写额外的长代码来包含foreach循环。


    在我的WindowsMobile项目中,我使用了一个for循环作为控制集合。20个控件需要100毫秒!一个foreach循环只使用了4毫秒。这是一个性能问题…


    我根据for和foreach的收集速度提到了这些细节。

    列表-for循环比foreach循环稍快

    arraylist-for循环的速度比foreach循环快2倍多。

    数组-两者的速度相同。但foreach循环似乎更快。


    我在前一段时间做了测试,结果是一个for循环比一个foreach循环快得多。原因很简单,foreach循环首先需要为集合实例化IEnumerator


    我遇到一个案子,前臂比前臂快得多

    为什么foreach在读取richtextbox行时比for循环快

    在那个问题上,我有一个类似于OP的案例。

    一个文本框读取大约72k行,我正在访问Lines属性(实际上是一个getter方法)。(显然,在WinForms中经常有getter方法不是O(1)。我想是O(N),所以文本框越大,从"属性"中获取值所需的时间就越长。在for循环中,我使用了for(int i=0;i,它非常慢,因为它每次读取一行时都读取整个文本框,每次检查条件时都读取整个文本框。

    JonSkeet显示,您可以只访问一次Lines属性(即使不是每次迭代一次,也只是一次)。而不是每次迭代两次(这是很多次)。do string[]strarrlines=textbox 1.lines;并循环遍历strarrlines。

    当然,一个相当直观的for循环和访问lines属性是非常低效的。

    1
    2
    3
    4
    for (int i = 0; i < richTextBox.Lines.Length; i++)
    {
        s = richTextBox.Lines[i];
    }

    对于文本框或富文本框,它是超慢的。

    在一个富文本框上测试循环的OP发现,"使用15000行for循环只需要8分钟就可以循环到15000行,而foreach只需要几秒钟就可以枚举它。"

    链接处的op发现这个foreach比上面提到的his(相同的op)for循环更有效。正如我所做的那样。

    1
    2
    3
    4
    5
       String s=String.Empty;
       foreach(string str in txtText.Lines)
        {
           s=str;
        }


    至少我没有看到我的同事或更高级别的人这样说,考虑到forforeach之间没有明显的速度差异,这简直是荒谬的。如果他要求在所有情况下都使用它,这同样适用!


    我建议你读一下这篇文章,找出一个具体的答案。本文的结论是,使用for循环通常比foreach循环更好、更快。


    从.NET Framework 4开始,您还可以使用parallel.for和parallel.foreach,如下所述:c多线程循环with parallel.for或parallel.foreach。


    Ben Watson,《编写高性能.NET代码》的作者:

    "Will these optimization matter to your program? Only if your program
    is CPU bound and collection iteration is a core part of your
    processing. As you'll see, there are ways you can hurt your
    performance if you're not careful, but that only matters if it was a
    significant part of your program to begin with. My philosophy is this:
    most people never need to know this, but if you do, then understanding
    every layer of the system is important so that you can make
    intelligent choices".

    最准确的解释可以在这里找到:http://www.codeproject.com/articles/844781/digging-into-net-loop-performance-bounds-checking


    在大多数情况下,我认为for比foreach稍微快一点,但这确实是漏掉了要点。有一件事我没有提到,在你所说的场景中(例如,一个大容量的web应用程序),for和foreach的性能差异不会影响网站的性能。您将受到请求/响应时间和数据库时间的限制,而不是V.ForEach。

    也就是说,我不理解你对前臂的厌恶。在我看来,在任何一种情况下,foreach都更清晰。我通常会为需要以某种丑陋的、非标准的方式遍历集合的情况预留空间。


    我需要使用三个嵌套循环(在List上)来解析一些大数据。我想,使用上面罗布·方塞卡·恩索的帖子,计时和比较for和foreach的区别会很有趣。

    区别在于:foreach(三个foreach像foreach foreach foreach一样嵌套)在171.441秒内完成了任务,而在158.616秒内完成了任务。

    现在13秒的时间减少了13%,这对我来说有点重要。但是,foreach绝对比使用三个索引fors更可读。