From:             php at richardneill dot org
Operating system: 
PHP version:      5.4.13
Package:          Performance problem
Bug Type:         Bug
Bug description:optimisation for "for ($i=0; $i<count($array);$i++)" when 
$array is global

Description:
------------
If an array is counted inside a for-loop, this is normally slightly
inefficient.

$n = count ($array);                  //[1] optimised and a bit faster.
for ($i=0; $i< $n;$i++){
  //do stuff
}   

for ($i=0; $i<count($array);$i++){    //[2] perfectly respectable speed.
  //do stuff                          //very nearly as fast as [1].
}   



BUT, if our for-loop is inside a function AND our $array is a global
variable, 
then method [2] becomes really really slow (though method [1] remains 
unaffected).

Below, the problematic function is add_slow(); the script does the same
thing 4 
ways to demonstrate that 3 of them work well and one works slowly.

Test script:
---------------
#!/usr/bin/php  -ddisplay_errors=E_ALL
<?
echo "This demonstrates the problem with counting global arrays inside
loops inside functions.\n";
$NUMBER = 10000; //adjust for your computer.
for ($i = 0; $i< $NUMBER; $i++){
        $data[$i] = "$i";
}

function add_slow(){    //This is the problematic function. $data is global,
and the count() is inside the for().
        global $data;   //It is REALLY slow: 4000 times slower than the others!
        $sum=0;
        for ($i = 0; $i < count($data); $i++){  
                $sum += $data[$i];
        }
        echo "Total (slow) is $sum.\n";
}

function add_fast(){    //This one is fine. The count() is optimised by taking
it out of the for().
        global $data;   //... but we're still using a global array, so that's 
not
the problem.
        $sum=0;
        $n = count($data);                      
        for ($i = 0; $i < $n; $i++){
                $sum += $data[$i];
        }
        echo "Total (fast) is $sum.\n";
}

function add_local(){  //This one is also fine. The count() is NOT
optimised, but it still runs almost as quickly.
        global $NUMBER;
        for ($i = 0; $i< $NUMBER; $i++){
                $data[$i] = "$i";
        }
        $sum=0;
        for ($i = 0; $i < count($data); $i++){   
                $sum += $data[$i];
        }
        echo "Total (local) is $sum.\n";
}       
        
echo "Calling add_slow()...\n";
$t1 = microtime(true); 
add_slow();
$t2 = microtime(true);
$time = round($t2 - $t1, 3);
echo "Finished in $time seconds.\n\n";  

echo "Calling add_fast()...\n";
$t1 = microtime(true);
add_fast();
$t2 = microtime(true);
$time = round($t2 - $t1, 3);
echo "Finished in $time seconds.\n\n";

echo "Calling add_local()...\n";
$t1 = microtime(true);
add_local();
$t2 = microtime(true);
$time = round($t2 - $t1, 3);
echo "Finished in $time seconds.\n\n";

echo "Not using a function...\n";
$t1 = microtime(true);
$sum=0;
for ($i = 0; $i < count($data); $i++){   //This one is in the main() scope,
it's also fast.
        $sum += $data[$i];
}
echo "Total (main loop) is $sum.\n";
$t2 = microtime(true);
$time = round($t2 - $t1, 3);
echo "Finished in $time seconds.\n\n";
?>

Expected result:
----------------
All 4 ways of summing this array should run in similar amounts of time (a
few 
milliseconds). 

But actually add_slow() is 3900 times slower. 


Actual result:
--------------
This demonstrates the problem with counting global arrays inside loops
inside 
functions.
Calling add_slow()...
Total (slow) is 49995000.
Finished in 7.86 seconds.

Calling add_fast()...
Total (fast) is 49995000.
Finished in 0.002 seconds.

Calling add_local()...
Total (local) is 49995000.
Finished in 0.006 seconds.

Not using a function...
Total (main loop) is 49995000.
Finished in 0.002 seconds.



-- 
Edit bug report at https://bugs.php.net/bug.php?id=64518&edit=1
-- 
Try a snapshot (PHP 5.4):   
https://bugs.php.net/fix.php?id=64518&r=trysnapshot54
Try a snapshot (PHP 5.3):   
https://bugs.php.net/fix.php?id=64518&r=trysnapshot53
Try a snapshot (trunk):     
https://bugs.php.net/fix.php?id=64518&r=trysnapshottrunk
Fixed in SVN:               https://bugs.php.net/fix.php?id=64518&r=fixed
Fixed in release:           https://bugs.php.net/fix.php?id=64518&r=alreadyfixed
Need backtrace:             https://bugs.php.net/fix.php?id=64518&r=needtrace
Need Reproduce Script:      https://bugs.php.net/fix.php?id=64518&r=needscript
Try newer version:          https://bugs.php.net/fix.php?id=64518&r=oldversion
Not developer issue:        https://bugs.php.net/fix.php?id=64518&r=support
Expected behavior:          https://bugs.php.net/fix.php?id=64518&r=notwrong
Not enough info:            
https://bugs.php.net/fix.php?id=64518&r=notenoughinfo
Submitted twice:            
https://bugs.php.net/fix.php?id=64518&r=submittedtwice
register_globals:           https://bugs.php.net/fix.php?id=64518&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=64518&r=php4
Daylight Savings:           https://bugs.php.net/fix.php?id=64518&r=dst
IIS Stability:              https://bugs.php.net/fix.php?id=64518&r=isapi
Install GNU Sed:            https://bugs.php.net/fix.php?id=64518&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=64518&r=float
No Zend Extensions:         https://bugs.php.net/fix.php?id=64518&r=nozend
MySQL Configuration Error:  https://bugs.php.net/fix.php?id=64518&r=mysqlcfg

Reply via email to