12

As my research leads me to believe that for loops are the fastest iteration construct in PHP... to make it clearer, which of the following do you think would be faster?

Example ONE

for ($i = 0; $i < count($myLargeArray); $i++ ) {
    echo myLargeArray[$i];
}

Example TWO

$count = count($myLargeArray);
for ($i = 0; $i < $count; $i++ ) {
    echo myLargeArray[$i];
}

My logic follows that on each iteration in example one accessing the length of myLargeArray on each iteration is more computationally expensive than accessing a simple integer value as in example two. Is that correct?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AndrewMcLagan
  • 13,459
  • 23
  • 91
  • 158

6 Answers6

14

The first way is slower because the count() function has to be called in every iteration of the loop. The count() method itself is pretty fast, but there is still some overhead in calling the function at all. By moving it outside the loop, you're performing what is called "loop invariant code motion", or sometimes "hoisting".

There's a whole family of optimizations like this that are interesting to learn about.

Having said all that, it seldom pays to stress about this very much. In your example here, the I/O of echoing the output is probably 10 times what you save through your "optimization". And if you do anything else at all inside your loop, your optimization means less and less.

I hate to be a wet blanket, but for more than 90% of your code, performance is a non-issue. Especially when you talk about web applications, which are more than 90% I/O to begin with.

Still, when you think your code is to blame, you should:

  1. Decide on the use case you need to optimize
  2. Measure your code performance
  3. Find the bottlenecks
  4. Identify the areas you can improve and decide whether it is worth your time to improve them.
  5. Make your code changes
  6. Go back to step 2

You'll nearly always discover that you need to improve your caching strategies and database optimization (which is just I/O optimization by another means), instead of twiddling code.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
slashingweapon
  • 11,007
  • 4
  • 31
  • 50
2

Example 2. Do not count the elements every iteration.

Updated: I've just been told that the value is precomputed: nNumOfElements specifies how many values are currently stored in the array. This is also the number thatcount($array)returns.

It seems to me the function count() literally do nothing except wasting some microseconds and clock cycles (for those who know assembler).

Read here: Understanding PHP's internal array implementation (PHP's Source Code for PHP Developers - Part 4).

Perhaps you can try foreach range:

foreach (range(0, (count(array)) as $number) {
    echo $number;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Micromega
  • 12,486
  • 7
  • 35
  • 72
  • Actually elements aren't counted on every loop. `count()` doesn't physically iterates over an array. – zerkms Nov 20 '12 at 03:49
  • What do you mean? Do you mean I confuse loop and iteration? – Micromega Nov 20 '12 at 03:50
  • You said "Do not count the elements every loop". And I said that `count()` language construction **doesn't count** anything, it just returns *precomputed* value. More at: http://nikic.github.com/2012/03/28/Understanding-PHPs-internal-array-implementation.html (ctrl+f for 'nNumOfElements') – zerkms Nov 20 '12 at 03:51
  • Well, I know the difference between counting and numbering. Thanks, for the hint. – Micromega Nov 20 '12 at 03:52
  • it's not about your knowledge but about your answer. "Do not count the elements every loop" - this is not entirely correct. PS: not sure what the term "numbering" means though :-S – zerkms Nov 20 '12 at 03:52
  • So, you downvote me because count() function doesn't count(iterate) but precompute value? Is this other answer correct? – Micromega Nov 20 '12 at 03:54
  • I didn't downvote. Your answer wasn't upvoted or downvoted by anyone. And I'm just saying that it's not well phrased – zerkms Nov 20 '12 at 03:54
  • Yes, my error but the other answer is upvoted. My answer is neutral. – Micromega Nov 20 '12 at 03:55
  • Some more details: If I was a newbie and read your answer - I would think the bigger array is, the more time consuming the operation is. Which is wrong. – zerkms Nov 20 '12 at 03:56
  • @zerkms: Why? Of course it takes more time when the array is bigger. Why should it takes the same time? You really overthinking. I will read your article. – Micromega Nov 20 '12 at 03:59
  • "Why should it takes the same time" --- because the number of elements is precomputed. See the link – zerkms Nov 20 '12 at 04:00
  • 1
    Function calls have relatively large overhead, so it does slow down the loop. The PHP compiler doesn't do a while lot of optimization, so the function does get called on every iteration, which wouldn't be the case in C/C++. – cleong Nov 20 '12 at 04:01
  • @zerkms: Yes, ok. It's precomputed but it's correct when you say count() counts elements? Btw I'm programmer from the old days I know assembler and c and such. – Micromega Nov 20 '12 at 04:03
  • @Skidrow: actually I don't know a correct words for that - but following your example - your answer would confuse newbies :-) – zerkms Nov 20 '12 at 04:04
  • @cleong: in C/C++ it's not guaranteed to be optimized to just a single call. – zerkms Nov 20 '12 at 04:05
  • 1
    @zerkms: counting is when you count elements. Numbering is when you give them symbols. It's why programmers have this difficult with null, 0 and 1. Pointer and memory address and number 0 confusion. Actually this job is sh1t. Bad payed and bad reputation. – Micromega Nov 20 '12 at 04:09
  • @Skidrow: "Bad payed and bad reputation." --- and thousands of another programmers who try to make you mad by their stupid comments ) (ps: anyway, the only your upvote is mine - because it's barely possible to give more precise but easy to understand answer) – zerkms Nov 20 '12 at 04:10
  • @zerkms: well, I read it. It's precomputed but it's also not precomputed because somewhere the elements must be counted. To me it's still very bad practise and it can make the difference between fast and good code. – Micromega Nov 20 '12 at 04:32
  • @zerkms: What about foreach range? Can you use count() there without repetition? – Micromega Nov 20 '12 at 04:36
  • @Skidrow: I cannot get how useful `count()` may be for `foreach` – zerkms Nov 20 '12 at 05:00
1

The fastest construct in this case is actually the foreach loop:

foreach($myLargeArray as $element) {
    echo $element;
} 

The foreach() is also nice in that it'll always terminate, whereas a typo could leave you with an infinite loop when you use for().

cleong
  • 7,242
  • 4
  • 31
  • 40
  • What about foreach range? Then he has also a counter variable. Btw. The fastest is to not have the loop at all and also you can unroll the loop. – Micromega Nov 20 '12 at 04:50
  • Not really. foreach() moves through the elements over a linked list, that's why it's faster. Even after you've unrolled your for loop, you're still going to be accessing the elements through the array's hash table. – cleong Nov 20 '12 at 12:39
1

So I decided to actually quantify a few things, in the interest of getting some real numbers. Here is the baseline code, a loop which builds a big array of 100000 integers.

$x = array();
for ($idx=0; $idx<100000; $idx++)
    $x[] = $idx;

Average time to execute: 85 ms. That includes the time to launch PHP, parse the program, run it, and exit. Now, I add another loop that iterates through the array:

for ($idx=0; $idx<count($x); $idx++) { 
    ;
}

Average time to execute: 105 ms. When you subtract the 85 ms setup time, you can see it takes only 20 ms to iterate through a 100,000 member array.

Now we add the loop invariant code motion:

$m = count($x);
for($idx=0; $idx<$m; $idx++) { 
    ;
}

Average time to execute: 90 ms.

On the one hand, this savings is huge. That's 5 ms loop iteration time instead of 20 ms. So you can argue that's a 75% savings!

On the other hand, it's 15 ms. Less time than most people will notice on an absurdly large array.

But this is an array that does nothing. Let's see what happens when we output some data:

$m = count($x);
for ($idx=0; $idx<$m; $idx++) { 
    echo $idx;
}

Now the execution time is 200 ms. Oh look, I only printed out the loop index. I didn't even output the contents of the array.

That's just silly. Let's change the program again to echo the contents of the array instead of just the look counter:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo $x[$idx];

New execution time is 212 ms. So it took 5% longer to access and echo the array contents than just echo the loop counter.

Let's take someone's earlier suggestion and unroll the loop. I've used this to great effect in C/C++ in the past:

$m = count($x);
for ($idx=0; $idx<$m; $idx+=5) {
    echo $x[$idx];
    echo $x[$idx+1];
    echo $x[$idx+2];
    echo $x[$idx+3];
    echo $x[$idx+4];
}

Now we're talking! We're down to 206 ms. Oh wait, that's about a 3% improvement for some un-fun code. And the output looks terrible. It's just a string of numbers without whitespace or anything.

Let's get rid of the loop unrolling, and make the output a little nicer:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo "{$x[$idx]}\n";

Execution time is 400 ms. Huh. That's a lot of extra time (relatively speaking) just to get some formatting. Maybe using the string substitution is costing us something. Let's try string concatenation instead:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo $x[$idx] . "\n";

The new time is 390 ms. A little better. Let's try separating the numbers by a space instead of a newline:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo $x[$idx] . " ";

Oh wow, we're back down to 224 ms. Right on! But what happened? Well, I'm running all this on my Unix terminal, and it is justs plain slower to output the numbers on separate lines than it is to output them all on one line that wraps.

In other words, the speed of the terminal program's scrolling has a bigger effect than anything else we did.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
slashingweapon
  • 11,007
  • 4
  • 31
  • 50
  • It's like I said some code editors have macros to unroll loops. You can write a php extension if you have some spare time or perhaps there is something out there. I think facebook hiphop thing is made just because of this: speed. Also what about genetic algorithm or machine learning? Or fractals in php? – Micromega Nov 20 '12 at 09:55
  • Then code would matter a lot more. For nearly everything people are actually doing nearly all the time, code efficiency isn't what they need to worry about: it's I/O. And personally, if I needed to generate some kind of fractal image with great performance I would write it in C and make it available as a plug-in for PHP. – slashingweapon Nov 20 '12 at 16:02
  • I don't understand a think. English isn't my native language. I don't think it's wrong to optimize code even when it's micro-optimized. But I also know it doesn't pay you the bills. The other thing about programming is also this isn't software alone but also it's about crazy machines. When you look into website like overclock.net and the effort ppl put into overclocking & cooling etc. why doing this with software either? Just because it's only 3% gain it's isn't worth anymore? When your code works and does the job why not optimize it especially when other ppl use it? – Micromega Nov 20 '12 at 17:28
  • There is nothing wrong with optimizing your code and taking pride in the quality of your work. But if you want your PHP web application to run faster, you have to understand that code performance is usually only 10% of your performance problem. The other 90% of your performance problem is solved with Cache-control headers, persistend database connections, APC/memcached, and query optimization -- all of which are designed to reduce I/O. – slashingweapon Nov 20 '12 at 17:50
  • You must difference. My private server is much better then my corporate server. Much more secure much faster and better equipped. Also there are other problems like fractals that is more math related then I/O. I just wonder why the hardware guys seems to have more fun. Maybe because I do it for living. – Micromega Nov 20 '12 at 18:12
  • Read here about unrolling in c: http://stackoverflow.com/questions/13476223/optimising-an-1d-heat-equation-using-simd. Maybe Op doesn't have something computational big. – Micromega Nov 20 '12 at 19:17
0

Clearly the example one is slower. The condition $i < count($myLargeArray) is evaluated every iteration, thus counting the array multiple times.

Check this and other benchmarks on http://www.phpbench.com/

Edit: they looked up on the source code, and it's precomputed.

However, processing time is wasted on those multiple function calls. That's why the performance drops. The array is "counted" multiple times.

Community
  • 1
  • 1
lukedays
  • 323
  • 1
  • 10
0

The fastest loop would be to unroll the loop. Some code editors, but not any PHP editors, support this with a special macro so you don't need to copy and paste.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Micromega
  • 12,486
  • 7
  • 35
  • 72