在c# / VB.NET/。哪个循环运行得更快,for还是foreach?

自从很久以前我读到for循环比foreach循环工作得快,我就认为它适用于所有集合、泛型集合、所有数组等。

我搜索了谷歌,找到了几篇文章,但大多数都是不确定的(阅读文章评论),而且是开放式的。

理想的情况是列出每种情况以及最佳解决方案。

例如(这只是一个例子):

用于迭代1000+的数组 字符串- for比foreach好 对于迭代IList(非泛型)字符串- foreach更好 比

在网上找到了一些相同的参考资料:

由Emmanuel Schanzer撰写的原创文章 CodeProject FOREACH Vs. FOR 博客——去博客还是不去博客,这是个问题 ASP。NET论坛- NET 1.1 c# for vs foreach

(编辑)

除了可读性之外,我对事实和数据真的很感兴趣。在某些应用中,最后一英里的性能优化确实很重要。


当前回答

有很好的理由选择foreach循环而不是for循环。如果你可以使用foreach循环,你的老板说你应该这样做是对的。

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

如果我是你,我会把你所有的for循环转化成递归。这样可以教会他,对你来说也是很好的脑力锻炼。

其他回答

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

它将永远接近。对于数组,有时For稍微快一点,但foreach更有表现力,并提供LINQ等。总的来说,坚持使用foreach。

此外,foreach可能在某些情况下进行了优化。例如,一个链表对于indexer来说可能很糟糕,但是对于foreach来说可能很快。实际上,由于这个原因,标准LinkedList<T>甚至没有提供索引器。

我遇到了一个案子,foreach比For快得多

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

我有一个类似于那个问题中的OP的案例。

A textbox reading about 72K lines, and I was accessling the Lines property(which is actually a getter method). (And apparently often in winforms there are getter methods that aren't O(1). I suppose it's O(n), so the larger the textbox the longer it takes to get a value from that 'property'. And in the for loop I had as the OP there had for(int i=0;i<textBox1.lines.length;i++) str=textBox1.Lines[i] , and it was really quite slow as it was reading the entire textbox each time it read a line plus it was reading the entire textbox each time it checked the condition.

Jon Skeet演示了您可以只访问一次Lines属性(甚至不是每次迭代一次,只是一次)。而不是每次迭代两次(这是大量的次数)。Do string[] strarlines = textBox1.Lines;然后在星线间循环。

但是一个直观形式的for循环访问Lines属性是非常低效的

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

对于文本框,或者富文本框,它非常慢。

OP在一个富文本框上测试了这个循环,发现“有15000行。For循环花了8分钟才循环到15000行。而foreach只花了不到一秒钟的时间来列举它。”

那个链接的OP发现这个foreach比上面提到的他(同一个OP)的for循环要有效得多。就像我一样。

   String s=String.Empty;
   foreach(string str in txtText.Lines)
    {
       s=str;
    }

首先是对德米特里的回答(现已删除)的反诉。对于数组,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<double>,您将得到完全不同的结果。它不仅在一般情况下要慢得多,而且foreach也比通过索引访问慢得多。话虽如此,我仍然几乎总是喜欢foreach而不是for循环,因为它使代码更简单——因为可读性几乎总是重要的,而微优化很少是。

除非您处于特定的速度优化过程中,否则我会建议使用产生最容易阅读和维护代码的方法。

如果已经设置了迭代器,比如其中一个集合类,那么foreach是一个很好的简单选项。如果你迭代的是一个整数范围,那么for可能更简洁。