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

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
DaveTheAve
Forum Contributor
Posts: 385
Joined: Tue Oct 03, 2006 2:25 pm
Location: 127.0.0.1
Contact:

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

Post 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.
Last edited by DaveTheAve on Sat Oct 21, 2006 9:01 am, edited 2 times in total.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post 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."
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

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

Post 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.
User avatar
DaveTheAve
Forum Contributor
Posts: 385
Joined: Tue Oct 03, 2006 2:25 pm
Location: 127.0.0.1
Contact:

Post 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.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post 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
User avatar
AKA Panama Jack
Forum Regular
Posts: 878
Joined: Mon Nov 14, 2005 4:21 pm

Post 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.
wei
Forum Contributor
Posts: 140
Joined: Wed Jul 12, 2006 12:18 am

Post by wei »

or do it inline

Code: Select all

for ($i=0, $total=count($array); $i<$total; ++$i)
{
}
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post 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.
User avatar
DaveTheAve
Forum Contributor
Posts: 385
Joined: Tue Oct 03, 2006 2:25 pm
Location: 127.0.0.1
Contact:

Post 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.
User avatar
jayshields
DevNet Resident
Posts: 1912
Joined: Mon Aug 22, 2005 12:11 pm
Location: Leeds/Manchester, England

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

Post by jayshields »

timvw wrote:Actually, the test is saying that there is a difference between pre- and postincrement.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

A lot of speed variations do not hold consistency when you move from compuer to computer.
User avatar
DaveTheAve
Forum Contributor
Posts: 385
Joined: Tue Oct 03, 2006 2:25 pm
Location: 127.0.0.1
Contact:

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

Post 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?
User avatar
patrikG
DevNet Master
Posts: 4235
Joined: Thu Aug 15, 2002 5:53 am
Location: Sussex, UK

Post 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 )
User avatar
jayshields
DevNet Resident
Posts: 1912
Joined: Mon Aug 22, 2005 12:11 pm
Location: Leeds/Manchester, England

Post 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.
User avatar
DaveTheAve
Forum Contributor
Posts: 385
Joined: Tue Oct 03, 2006 2:25 pm
Location: 127.0.0.1
Contact:

Post 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.
Post Reply