在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

(编辑)

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


当前回答

当你遍历常见的结构如数组、列表等时,for-和foreach-循环的速度差异很小,并且在集合上执行LINQ查询几乎总是稍微慢一些,尽管它写得更好!正如其他海报上说的那样,追求表现力而不是多出一毫秒的性能。

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

foreach循环的另一个关键优势是,如果你的集合实现发生了变化(例如,从int数组到List<int>),那么你的foreach循环将不需要任何代码更改:

foreach (int i in myCollection)

不管你的集合是什么类型,上面的都是一样的,而在你的for循环中,如果你把myCollection从数组改变为List,下面的将不会构建:

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

其他回答

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

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

我发现foreach循环迭代列表更快。下面是我的测试结果。在下面的代码中,我分别迭代一个大小为100、10000和100000的数组,使用for和foreach循环来测量时间。

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代码,发现使用数组的for循环比下面的更快,

Foreach循环与数组。 For带列表的循环。 Foreach循环与列表。

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

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);
    }

《编写高性能。net代码》一书的作者Ben Watson:

“这些优化对你的程序重要吗?只有当你的程序 CPU的限制和收集迭代是你的核心部分 处理。如你所见,有很多方法可以伤害你的 如果你不小心,就会失去效果,但只有当它是 这是你计划的重要组成部分。我的哲学是: 大多数人不需要知道这些,但如果你知道,那就理解了 系统的每一层都很重要,这样你才能 聪明的抉择”。

最严厉的解释可以在这里找到:http://www.codeproject.com/Articles/844781/Digging-Into-NET-Loop-Performance-Bounds-checking

两者之间不太可能有巨大的性能差异。与往常一样,当面对“哪个更快?”的问题时,您应该始终认为“我可以测量这个”。

在循环体中编写两个做相同事情的循环,执行并计时,并查看速度的差异。使用一个几乎为空的主体和一个与您实际要做的类似的循环主体来执行此操作。还可以尝试使用您正在使用的集合类型,因为不同类型的集合可能具有不同的性能特征。

至少我没有看到我的同事或上级这么说,考虑到for和foreach之间没有显著的速度差异,这是荒谬的。如果他要求在所有情况下都使用它,同样适用!