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