Page 1 of 2

[MUST READ] The Fastest For (Improve your PHP!)

Posted: Fri Oct 20, 2006 9:51 pm
by DaveTheAve
My Fellow Programmers
I thank you for spending the time to read this article. I will must-likely in the future rewrite this but currently I'm not interested. Well your reading this because ether the title caught your eye or you want faster PHP code; I can do that.

Earlier today, me and a college buddy were conversing about which for statements were faster. So I built a little PHP script to prove that my statement was correct. You should really try this out. By using the statement for ($i = 10000000; $i > 0; --$i) instead of for ($i = 0; $i < 10000000; $i++) there is a nice speed improvement. Basically, the test is saying computers count down better then they count up. (Does gravity have anything to do with it? lol)

Then this got me thinking, what about for and foreach statements which is faster? First I tried the for ($i=0; $i < count($array); $i++) with foreach ($array as $arr). I noticed that foreach was insanely faster by almost a whole second. Wondering even more I tried the the same for loop but using the faster methoud counting down as such: for ($i=count($array); $i > 0; --$i). This was still faster then the traditional for statement but slower then the foreach.

Code Version: 1.05
My results may be testing using this script I formulated:

Code: Select all

<?php
/**
 * For statement analyzer 1.05
 * Programmed by David Branco <David@NeoeliteUSA.com>
 * http://www.NeoeliteUSA.com
 * October 21, 2006
 */
/* Timer Class to measure the speed of PHP */
class Timer {
    private static $page_generate_start;
    private static $page_generate_end;
    public static $page_generate_time;
    
    function measure()
    {
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }
    
    function start()
    {
        self::$page_generate_start = self::measure();
        return true;
    }
    function end()
    {
        self::$page_generate_end = self::measure();
        self::$page_generate_time = self::$page_generate_end - self::$page_generate_start;
        return true;
    }
}
$timer = new Timer();
timer::start();

for ($i = 0; $i < 10000000; $i++) {}

timer::end();
echo 'for ($i = 0; $i < 10000000; $i++)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i = 0; $i < 10000000; ++$i) {}

timer::end();
echo 'for ($i = 0; $i < 10000000; ++$i)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i = 10000000-1; $i >= 0; --$i) {}

timer::end();
echo 'for ($i = 10000000-1; $i >= 0; --$i)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i = 10000000-1; $i >= 0; $i--) {}

timer::end();
echo 'for ($i = 10000000-1; $i >= 0; $i--)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i = 10000000; $i > 0; --$i) {}

timer::end();
echo 'for ($i = 10000000; $i > 0; --$i)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i = 10000000; $i > 0; $i--) {}

timer::end();
echo 'for ($i = 10000000; $i > 0; $i--)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

/***************************************************************/
/***************************************************************/
/***************************************************************/
/***************************************************************/
/***************************************************************/
/***************************************************************/
function printr ( $object , $name = '' ) {
   if ( is_array ( $object ) ) {
       print ( '<pre>' )  ;
       print_r ( $object ) ;
       print ( '</pre>' ) ;
   } else {
       var_dump ( $object ) ;
   }
}
$array = array('a','b','c','d','e','f','g','u','k','n','o','p');

echo printr($array)."\n";

timer::start();

$total=count($array);
for ($i=0; $i<$total; $i++) {}

timer::end();
echo 'Traditional for statment: for ($i=0; $i<$total; $i++)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i=0, $total=count($array); $i<$total; $i++) {}

timer::end();
echo 'Wei Style for statment: for ($i=0, $total=count($array); $i<$total; $i++)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

for ($i=count($array); $i > 0; --$i) {}

timer::end();
echo 'Fastest for statment: for ($i=count($array); $i > 0; --$i)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

timer::start();

foreach ($array as $arr) {}

timer::end();
echo 'foreach statment: foreach ($array as $arr)'.'<br />'.timer::$page_generate_time.'<br /><br />'."\n";

?>
P.S. If you wish for me to add more to the script tell me and I'll update it.

Posted: Fri Oct 20, 2006 10:15 pm
by feyd
Sorry, I must not be getting the point, and this may come across a bit harsh, but how is this a "must read"?

I'll generally go with "use what you're comfortable with and is understandable to others, but avoid redundancy."

Re: [MUST READ] The Fastest For (Improve your PHP!)

Posted: Fri Oct 20, 2006 10:18 pm
by timvw
DaveTheAve wrote:By using the statement for ($i = 10000000; $i > 0; --$i) instead of for ($i = 0; $i < 10000000; $i++) there is a nice speed improvement. Basically, the test is saying computers count down better then they count up. (Does gravity have anything to do with it? lol)
Actually, the test is saying that there is a difference between pre- and postincrement.

Posted: Fri Oct 20, 2006 10:20 pm
by DaveTheAve
Well, I thought that people would like to speed up their code would LOVE to read this. I mean the results i'm getting are rather impressive. Plus if you can't read the for loop counting down and not up, your really not this advanced anyway. Though I know you (feyd) are, i'm just stating that for others.

Posted: Fri Oct 20, 2006 10:28 pm
by alex.barylski
Interesting...

Although I find the fact a foreach is faster than a for quite puzzling...perhaps I just the implementation in my head wrong...

Has someone else tried this?

I would suggest taking the count() out of the for loop and instead assigning it to a variable and using that variables in the actual counter and see if those results still stand...

Pre and Post increments really differ than much? I would never have thunk it

Posted: Fri Oct 20, 2006 10:35 pm
by AKA Panama Jack
You should NEVER use the COUNT function in a FOR loop

Code: Select all

for ($i=0; $i < count($array); $i++) {}
That is just plain bad because every iteration of the FOR loop causes the COUNT function to recount the array.

If you want a more ACCURATE test you should do this...

Code: Select all

$counter = count($array);
for ($i=0; $i < $counter; $i++) {}
That is how you should execute a FOR loop when you are working with array elements in your example. You will find the for loop is now considerably faster.

Posted: Fri Oct 20, 2006 11:16 pm
by wei
or do it inline

Code: Select all

for ($i=0, $total=count($array); $i<$total; ++$i)
{
}

Posted: Fri Oct 20, 2006 11:24 pm
by alex.barylski
AKA Panama Jack wrote:You should NEVER use the COUNT function in a FOR loop

Code: Select all

for ($i=0; $i < count($array); $i++) {}
That is just plain bad because every iteration of the FOR loop causes the COUNT function to recount the array.

If you want a more ACCURATE test you should do this...

Code: Select all

$counter = count($array);
for ($i=0; $i < $counter; $i++) {}
That is how you should execute a FOR loop when you are working with array elements in your example. You will find the for loop is now considerably faster.
vodka did take the time for locate the function for us remember...and it does actually use a cached variable...from what I remember...

The problem isn't with count() itself but the fact that PHP optimizer doesn't cache count() so count() is indeed re-called every iteration...whether it uses a cache or not is beside the point. The caching logic also takes time to execute. So for that reason, from what I can tell, it's generall bad practice to call count() inside any for loop like above.

Posted: Sat Oct 21, 2006 9:00 am
by DaveTheAve
Ok Thanks for the tips guys. I've updated the experiment code with the advise from AKA Panama Jack and also added a whole new for statement with Wei's structure. However, There STILL is a speed improvement in the foreach statement compared with BOTH the for statements. Try it out a few times and give some more feedback.

BTW: I'm not trying to get anyone to use these new structures or prove a point. I'm merely trying to figure out which way is the best way to program these. Obviously I should always use this: for ($i = 0; $i < 10000000; ++$i). Now I'm questioning foreach's ability. I'm also wondering whether to use if or switch at times.

Re: [MUST READ] The Fastest For (Improve your PHP!)

Posted: Sat Oct 21, 2006 9:13 am
by jayshields
timvw wrote:Actually, the test is saying that there is a difference between pre- and postincrement.

Posted: Sat Oct 21, 2006 9:18 am
by Chris Corbyn
A lot of speed variations do not hold consistency when you move from compuer to computer.

Re: [MUST READ] The Fastest For (Improve your PHP!)

Posted: Sat Oct 21, 2006 9:28 am
by DaveTheAve
timvw wrote:Actually, the test is saying that there is a difference between pre- and postincrement.
Ya, thats true, but like i'm saying i'm only bringing this to peoples' attention.
d11wtq wrote:A lot of speed variations do not hold consistency when you move from computer to computer.
This is also true, however, I'm sure you'd like to improve the general speed of your programs. If your program is only meant to be used on ONLY YOUR Machine, wouldn't you like it to run the fastest it can?

Posted: Sat Oct 21, 2006 9:53 am
by patrikG
DaveTheAve wrote:There STILL is a speed improvement in the foreach statement compared with BOTH the for statements. Try it out a few times and give some more feedback.

BTW: I'm not trying to get anyone to use these new structures or prove a point. I'm merely trying to figure out which way is the best way to program these. Obviously I should always use this: for ($i = 0; $i < 10000000; ++$i). Now I'm questioning foreach's ability. I'm also wondering whether to use if or switch at times.
Performancewise, foreach is the bottom of the pile ( http://www.php.lt/benchmark/phpbench.php )

Posted: Sat Oct 21, 2006 9:57 am
by jayshields
That website looks dodgy, although interesting.

Comments like
isSet() and empty() are identical.
and grammar such as
So alway check if val is set at all befor using type-checking.
make me wonder if the tests are rock solid.

Posted: Sat Oct 21, 2006 10:01 am
by DaveTheAve
patrikG wrote:Performancewise, foreach is the bottom of the pile ( http://www.php.lt/benchmark/phpbench.php )
Ouch, looks like I didn't need to do these tests anyways. That site also answered my question regarding using if or switch. lol Thanks.