【问题标题】:for loop VS while loop in programming languages, c++/java?编程语言中的 for 循环 VS while 循环,c++/java?
【发布时间】:2012-01-05 21:52:12
【问题描述】:

哪个性能更好?这可能与其他编程语言不一致,所以如果它们不同,或者您可以用您对特定语言的知识回答我的问题,请解释一下。

我将使用 c++ 作为示例,但我想知道它在 java、c 或任何其他主流语言中是如何工作的。

int x = 0;
 while (x < 10) {
    cout << x << "\n ";
    x++;
  }

VS

for ( int x = 1; x < 10; x++)   
 cout << x << "\n ";

哪一个表现更好?如果是 for 循环,那么假设已经声明了一个整数,我们可以在 while 循环增量中使用,我们不需要为 while 循环创建?

示例:

int age = 17; //this was made for something else in the code, not a while loop. But fortunately for us, our while loop just so happened to need the number 17.

 while (age < 25) {
        cout << age << "\n ";
        age++;
      }

这个实例会使 while 循环成为比创建 for 循环更好的选择吗?我看到的问题与此有些相似,但我不认为这是重复的,或者其他问题的任何答案都回答了我的问题。

我想要一个关于这个问题的解释,解释它是否是特定于编译器的,它是如何工作的,或者任何对这个问题有好的答案。

【问题讨论】:

  • 这是最糟糕的过早优化。 没关系.
  • 请不要在没有分析的情况下进行优化。在您编写的所有代码的 99.99% 中,您不会看到这些循环之间有任何区别。如果你要优化这样的东西,至少看看程序集。不同类型的循环会有所不同。
  • 从性能的角度来看,我非常怀疑是否存在任何差异。我更担心可读性。
  • 在这种情况下,您必须查看生成的汇编/IL 代码。在大多数情况下,编译器将生成相同的代码,而在其他少数情况下,它只会进行一些重新排序。总而言之,这里没有明显的区别。
  • @Voo 不幸的是我不知道任何程序集

标签: java c++ c performance


【解决方案1】:

所有明智的编译器都应该将等效循环编译为涉及分支和跳转的相同汇编/IL 代码。 (至少启用优化)

【讨论】:

  • 不一定。众所周知,编译器会针对更强大的循环进行优化。
  • 这是一个更高级别的语句。也许我错了,但这意味着编译器可以更渴望优化它。
【解决方案2】:

在某些 CPU 架构上,循环的特性可能会提供更多优化的机会,而不是选择 forwhile

特别是,FORTRANPascal 建议使用常量(而不是变量)来表示某些 CPU 可以优化的循环迭代次数。例如,在 Cyber​​(1970 年代的 Iron Dinosaur 大型机)上,一个 15 位寄存器保存了可以轻松比较的 for 循环索引。 while 使用一个或两个更难访问的 60 位寄存器。此外,Cyber​​ 分支指令比循环内务管理或可能的循环内容要昂贵得多。在这种情况下,高级别的优化可能会展开循环以避免所有开销。

但是,现代代码生成器不再像以前那样工作:源代码被转换为中间解析结构,将这些选择抽象出来。简而言之,forwhile 没有区别。

【讨论】:

    【解决方案3】:

    我发现很难想象您提供的代码示例会有不同的性能特征。

    不过,我确实对你有一点好奇。在类似 Pascal 的语言(例如 Delphi)中,循环限制只评估一次。这与每次迭代都会评估循环限制的类 C 语言不同。这可能会对性能产生影响,但通过在循环外引入局部变量,用类似 C 的语言编写高性能代码当然是微不足道的。

    例如:

    德尔福

    for i := 0 to List.Count-1 do
      DoStuff(List[i]);
    

    List.Count 只计算一次。

    C++

    for (int i=0; i<List.getCount(); i++)
      DoStuff(List.getItem(i));
    

    这里,List.getCount() 每次在循环中都会被调用。

    如果发现评估循环限制的成本很高,那么这种差异可能是相关的。当然,在循环外评估 List.getCount() 并将结果存储在局部变量中是微不足道的。

    比较了 Pascal 和 C/C++ 的 for 循环后,我想说 Pascal 版本相比之下非常简单。这不一定是坏事,因为对于更复杂的情况,总是有while 可用。

    【讨论】:

    • 阅读你的第一段“我确实对你有一点好奇”你的意思是别的吗?
    • 不确定您的评论是什么意思。对不起。
    • 有趣的德尔福花絮。尽管如果您提出这种差异,您可能应该提及 CSE。此外,您甚至不必在循环范围之外引入变量:for (int i=0, max=List.GetCount(); i &lt; max; i++) - 根据我的经验,这将是 C/C++ 代码中的常用习语。
    • @Voo 什么是 CSE?我恳求对此一无所知!
    • @DavidHeffernan “我确实对你有一点好奇”意味着你对我这个人很好奇,这很奇怪。我想你的意思是“我和你有同样的好奇心”之类的意思
    【解决方案4】:

    您发布的示例实际上对whilefor 有不同的行为。

    这个:

    for (int x = 0; x < 100; ++x) {
      foo y;
      y.bar(x);
    }
    

    相当于这个:

    { // extra blocks needed
      int x = 0;
      while (x < 100) {
        {
          foo y;
          y.bar(x);
        }
        ++x;
      }
    }
    

    您可以预期性能是相同的。 如果没有额外的大括号,含义是不同的,因此生成的程序集可能会有所不同。

    虽然在现代编译器上不存在两者之间的差异,但for 可能会更好地优化,因为它会更明确地说明其行为。

    【讨论】:

      【解决方案5】:

      这是特定于编译器的,但我想在几乎所有情况下,两种方法的性能都是相同的。

      为了确保针对特定情况,您应该测量性能,尽管在您花费大量时间对这样的代码进行微优化之前,您应该首先确定这实际上是您的应用程序的瓶颈(可能不是) .

      您的第二个示例可以写成没有初始化表达式的for 循环。

      int age = 17; // This was made for something else in the code
      
      for (; age < 25; age++) {
          cout << age << endl;
      }
      

      【讨论】:

        【解决方案6】:

        我认为现在编译器已经足够优化,所以如果你使用 for 循环或 while 循环真的没有什么区别。

        【讨论】:

        • 我敢肯定差别很小
        【解决方案7】:

        我建议你写一个小例子和时间差。然后选择您认为最快的任何解决方案。

        【讨论】:

          【解决方案8】:

          你提出的问题是不恰当的。您在循环中拥有的 IO 支配了所有循环处理语句可以添加的至少一个数量级。我敢打赌,您甚至无法测量任何显着差异,因为它无法与 IO 产生的噪声(在测量方面)区分开来。

          只有在循环内的代码非常快的情况下,事情才有意义。这里的快速意味着甚至没有内存读取指令,因为那时 CPU 内存带宽将再次占据主导地位。

          所以如果你真的很好奇,而且你看起来很好奇,请阅读汇编程序并查看代码。如果你只有两个小函数,每种类型的循环,输出就不那么难读了,真的,不要害怕。不过,我建议使用 C 来完成,这可能最接近组件,并且最容易让您识别零件。

          你没有告诉我们你是什么系统/编译器。使用 gcc,选项将是 -S -O3 -march=native 以使其生成 .s 文件。

          【讨论】:

            【解决方案9】:

            对编译器优化没有任何影响!

            我的 2cts,当涉及到循环实现选择时,使用适合算法逻辑的那个很重要。更容易阅读代码。

            【讨论】:

              猜你喜欢
              • 2021-03-06
              • 2012-10-02
              • 2015-04-24
              • 1970-01-01
              • 2015-03-09
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多