【问题标题】:Simple loop performance issue简单的循环性能问题
【发布时间】:2011-11-28 22:32:02
【问题描述】:

假设我有一个像这样的简单 PHP 循环

// Bad example
$array = array('apple','banana','cucumber');
for ($i = 1; $i < count($array); $i++) {
    echo $array[$i];
}

我知道这是一种不好的做法。最好不要在循环中使用count()

// Nice example
$array = array('apple','banana','cucumber');
$limit = count($array);
for ($i = 1; $i < $limit; $i++) {
    // do something...
}    

在 Java 中,我会这样做

// Bad example?
String[] array = {"apple","banana","cucumber"};
for(int i = 0; i < array.length; i++){
    System.out.println(array[i]);
}

问题:这难道不是一种不好的做法吗?还是跟下面的例子一样?

// Nice example?
String[] array = {"apple","banana","cucumber"};
int limit = array.length;
for(int i = 0; i < limit; i++){
    System.out.println(array[i]);
}

【问题讨论】:

标签: java php performance


【解决方案1】:

任何体面的编译器/解释器都应该自动优化第一个示例以匹配第二个(从语义上讲,如果不完全是字面意思的话),并且可能第三个匹配第四个。它被称为循环不变优化,其中编译器识别出一个实体(变量、表达式等)在循环内没有变化(即是不变)并将其删除到循环之外(松散地说)。

如果曾经是的话,这已经不是坏习惯了。

【讨论】:

  • 这不是问题的答案,但很有趣。但是:+1。
  • @MartijnCourteaux:感谢您的支持! IIRC,问题是“这是不好的做法”吗?我在第二段中特别提到了这一点(不,这不是坏习惯),我的其余答案解释了原因。它还解释了为什么第三个示例与第四个示例基本相同(这是另一个问题)。
【解决方案2】:

您使用的“坏”示例并不相同,因此无法比较——即使表面上看起来如此。使用这个描述:

for (initialization; termination; increment) {
    statement(s)
}

(描述 PHP 和 java 循环),initialization 语句在循环开始时执行一次。 termination 语句和 increment 为循环的每次迭代执行。

termination 语句中使用 PHP 的 count 是不好的做法的原因是,对于每次迭代,都会发生 count 函数调用。在您的 Java 示例中,array.length 不是函数调用,而是对公共成员的引用。因此,您的示例中使用的 termination 语句不是等效行为。我们预计函数调用比属性引用更昂贵。

任何语言的for循环的终止语句中放置函数调用(或调用屏蔽函数的属性)是不好的做法描述了循环机制。这就是使 PHP 示例“糟糕”的原因,如果您在 Java 中使用 count-type 函数 for 循环的终止语句,那同样糟糕。那么,真正的问题是,Java 的 Array.length 是否确实屏蔽了函数调用 - 答案是“否”(请参阅​​潜在的重复问题,和/或查看 http://leepoint.net/notes-java/data/arrays/arrays.html

【讨论】:

  • 谢谢克里斯!事实上,我怀疑Array.length 可能是一种方法——我对String.length() 感到困惑,即 一种方法。 Array.length 只是一个属性。所以我的 Java“坏例子”还不错。
【解决方案3】:

主要区别在于count() 是一个函数,而array.length 是一个属性,因此与limit 变量没有区别。

【讨论】:

    【解决方案4】:

    它们不一样,在 Java 的“好例子”中,你不是每次都计算数组的长度。相反,您将其存储在 limit 变量中并使用它来停止计算,而不是通过 for 循环每次迭代调用数组上的 length 函数的结果。

    编辑:您认为“不好的做法”的两件事都是不好的做法,“好的例子”是更有效的方法(至少在理论上)。但确实在执行上不会有任何明显的区别。

    【讨论】:

      【解决方案5】:

      在 java 中,数组将此属性作为常量(public final int)并不重要。 不同之处在于java数组具有固定大小并且不能增长,因此无需每次都计算元素来访问长度。

      【讨论】:

        猜你喜欢
        • 2011-06-17
        • 2011-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多