简体   繁体   English

简单的循环性能问题

[英]Simple loop performance issue

Say I have a simple PHP loop like this one 假设我有一个像这样的简单PHP循环

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

I know this is a bad practice. 我知道这是一种不好的做法。 It's better not using count() inside a loop. 最好不要在循环中使用count()

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

In Java, I would do it this way 在Java中,我会这样做

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

Question: Isn't this above a bad practice too? 问题:这也不是一个坏习惯吗? Or it is just the same as the example below? 或者它与下面的例子相同?

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

Any decent compiler/interpreter should automatically optimise the first example to match the second (semantically speaking anyway, if not exactly literally), and probably the third to match the fourth. 任何体面的编译器/解释器都应该自动优化第一个例子来匹配第二个例子(无论如何,从语义上讲,如果不是字面意义),可能是第三个匹配第四个例子。 It's known as a loop invariant optimisation , where the compiler recognises that an entity (variable, expression, etc) does not vary within the loop (ie is invariant ) and removes it to outside the loop (loosely speaking). 它被称为循环不变优化 ,其中编译器识别实体(变量,表达式等)在循环内不变 (即不变 )并将其移除到循环外(松散地说)。

It's not bad practice at all anymore, if it ever was. 如果有的话,那就再也不差了。

The "bad" examples you use are not equivalent, and thus are not comparable - even if they seem so on the surface. 您使用的“坏”示例并不等同,因此无法比较 - 即使它们表面上看起来如此。 Using this description: 使用此描述:

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

(which is descriptive of both PHP and java loops), the initialization statement is executed once, at the start of the loop. (它描述了PHP和java循环), 初始化语句在循环开始时执行一次。 The termination statement and the increment are executed for each iteration of the loop. 对于循环的每次迭代,执行终止语句和增量

The reason it is bad practice to use PHP's count in the termination statement is that, for each iteration, the count function call occurs. 终止语句中使用PHP count是不好的原因是,对于每次迭代,都会发生count函数调用。 In your Java example, array.length is not a function call but a reference to a public member. 在Java示例中, array.length不是函数调用,而是对公共成员的引用。 Therefore, the termination statements used in your examples are not equivalent behavior. 因此,示例中使用的终止语句不是等效行为。 We expect a function call to be more costly than a property reference. 我们希望函数调用比属性引用更昂贵。

It is bad practice to place a function call (or call a property that masks a function) in the termination statement of a for loop in any language which has the described loop mechanics. 在具有所描述的循环机制的任何语言的for循环的终止语句中放置函数调用(或调用掩盖函数的属性)是不好的做法。 That's what makes the PHP example "bad", and it would be equally bad if you used a count -type function in Java for loop's termination statement. 这就是使PHP示例“坏”的原因,如果在Java中使用count -type函数来获取循环的终止语句,那也同样糟糕。 The real question, then, is whether Java's Array.length does indeed mask a function call - the answer to that is "no" (see the potential duplicate question, and/or check out http://leepoint.net/notes-java/data/arrays/arrays.html ) 那么,真正的问题是Java的Array.length是否确实掩盖了函数调用 - 答案是“不”(参见潜在的重复问题,和/或查看http://leepoint.net/notes-java /data/arrays/arrays.html

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

They are not the same, in the Java "nice example" you are not calculating the length of the array every time. 它们不一样,在Java“很好的例子”中,你不是每次都计算数组的长度。 Instead, you are storing that in the limit variable and using that to stop the calculation instead of the result of calling the length function on the array every iteration through the for loop. 相反,您将其存储在limit变量中并使用它来停止计算,而不是每次迭代通过for循环调用数组上的length函数的结果。

EDIT: Both of the things that you thought were "bad practice" are bad practice and the "nice examples" are the more efficient ways (at least in theory). 编辑:你认为“坏习惯”的两件事都是不好的做法,“好例子”是更有效的方法(至少在理论上)。 But it is true that in implementation there will not be any noticeable difference. 但确实在实施过程中不会有任何明显的差异。

In java this doesn't matter an array has this attribute as a constant (public final int). 在java中,这并不重要,数组将此属性作为常量(public final int)。 The difference is in java arrays have a fixed size and can not grow so there would be no need to count the elements every time to access length. 区别在于java数组具有固定的大小并且不能增长,因此不需要每次访问长度都计算元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM