php foreach, why using pass by reference of a array is fast? -
below test of php foreach loop of big array, thought if $v
don't change, real copy not happen because of copy on write, why fast when pass reference?
code 1:
function test1($a){ $c = 0; foreach($a $v){ if($v=='xxxxx') ++$c; } } function test2(&$a){ $c = 0; foreach($a $v){ if($v=='xxxxx') ++$c; } } $x = array_fill(0, 100000, 'xxxxx'); $begin = microtime(true); test1($x); $end1 = microtime(true); test2($x); $end2 = microtime(true); echo $end1 - $begin . "\n"; //0.03320002555847 echo $end2 - $end1; //0.02147388458252
but time, using pass reference slow.
code 2:
function test1($a){ $cnt = count($a); $c = 0; for($i=0; $i<$cnt; ++$i) if($a[$i]=='xxxxx') ++$c; } function test2(&$a){ $cnt = count($a); $c = 0; for($i=0; $i<$cnt; ++$i) if($a[$i]=='xxxxx') ++$c; } $x = array_fill(0, 100000, 'xxxxx'); $begin = microtime(true); test1($x); $end1 = microtime(true); test2($x); $end2 = microtime(true); echo $end1 - $begin . "\n"; //0.024326801300049 echo $end2 - $end1; //0.037616014480591
can explain why passing reference fast in code1 slow in code2?
edit: code 2, count($a)
makes main difference, time of loop took same.
i thought if
$v
don't change [foreach($a $v)
], real copy not happen because of copy on write, why fast when pass reference?
the impact not on $v
on $a
, huge array. either pass value or reference function. inside function it's value (test1) or reference (test2).
you have 2 codes (code 1 , code 2).
code 1: using foreach
. foreach
you've got 2 options: iterate on value or reference (example). when iterate on value, iteration done on copy of value. if iterate on reference, no copy done.
as use reference in test2, it's faster. values not need copied. in test1, pass array value, array gets copied.
code 2: using for
. nothing here. in both cases. access variable , read value array. that's pretty same regardless if it's reference or copy (thanks copy on write optimization in php).
you might wonder, why there is difference in code 2. difference not because of for
because of count
. if pass reference count
php internally creates copy of because count
needs copy, not reference.
read well: do not use php references johannes schlüter
i've compiled set of tests well. more put code test functions.
- blank - what's difference in calling function?
- count -
count
make difference? - for - happens
for
only (notcount
)? - foreach -
foreach
- breaking on first element.
every test in 2 versions, 1 called _copy
(passing array copy function) , 1 called _ref
(passing array reference).
it's not these micro-benchmarks tell truth, if you're able isolate specific points, can quite educated guess, example not for
count
had impact:
function blank_copy($a){ } function blank_ref(&$a){ } function foreach_copy($a){ foreach($a $v) break; } function foreach_ref(&$a){ foreach($a $v) break; } function count_copy($a){ $cnt = count($a); } function count_ref(&$a){ $cnt = count($a); } function for_copy($a){ for($i=0;$i<100000;$i++) $a[$i]; } function for_ref(&$a){ for($i=0;$i<100000;$i++) $a[$i]; } $tests = array('blank_copy', 'blank_ref', 'foreach_copy', 'foreach_ref', 'count_copy', 'count_ref', 'for_copy', 'for_ref'); $x = array_fill(0, 100000, 'xxxxx'); $count = count($x); $runs = 10; ob_start(); for($i=0;$i<10;$i++) { shuffle($tests); foreach($tests $test) { $begin = microtime(true); for($r=0;$r<$runs;$r++) $test($x); $end = microtime(true); $result = $end - $begin; printf("* %'.-16s: %f\n", $test, $result); } } $buffer = explode("\n", ob_get_clean()); sort($buffer); echo implode("\n", $buffer);
output:
* blank_copy......: 0.000011 * blank_copy......: 0.000011 * blank_copy......: 0.000012 * blank_copy......: 0.000012 * blank_copy......: 0.000012 * blank_copy......: 0.000015 * blank_copy......: 0.000015 * blank_copy......: 0.000015 * blank_copy......: 0.000015 * blank_copy......: 0.000020 * blank_ref.......: 0.000012 * blank_ref.......: 0.000012 * blank_ref.......: 0.000014 * blank_ref.......: 0.000014 * blank_ref.......: 0.000014 * blank_ref.......: 0.000014 * blank_ref.......: 0.000015 * blank_ref.......: 0.000015 * blank_ref.......: 0.000015 * blank_ref.......: 0.000015 * count_copy......: 0.000020 * count_copy......: 0.000022 * count_copy......: 0.000022 * count_copy......: 0.000023 * count_copy......: 0.000024 * count_copy......: 0.000025 * count_copy......: 0.000025 * count_copy......: 0.000025 * count_copy......: 0.000026 * count_copy......: 0.000031 * count_ref.......: 0.113634 * count_ref.......: 0.114165 * count_ref.......: 0.114390 * count_ref.......: 0.114878 * count_ref.......: 0.114923 * count_ref.......: 0.115106 * count_ref.......: 0.116698 * count_ref.......: 0.118077 * count_ref.......: 0.118197 * count_ref.......: 0.123201 * for_copy........: 0.190837 * for_copy........: 0.191883 * for_copy........: 0.193080 * for_copy........: 0.194947 * for_copy........: 0.195045 * for_copy........: 0.195944 * for_copy........: 0.198314 * for_copy........: 0.198878 * for_copy........: 0.200016 * for_copy........: 0.227953 * for_ref.........: 0.191918 * for_ref.........: 0.194227 * for_ref.........: 0.195952 * for_ref.........: 0.196045 * for_ref.........: 0.197392 * for_ref.........: 0.197730 * for_ref.........: 0.201936 * for_ref.........: 0.207102 * for_ref.........: 0.208017 * for_ref.........: 0.217156 * foreach_copy....: 0.111968 * foreach_copy....: 0.113224 * foreach_copy....: 0.113574 * foreach_copy....: 0.113575 * foreach_copy....: 0.113879 * foreach_copy....: 0.113959 * foreach_copy....: 0.114194 * foreach_copy....: 0.114450 * foreach_copy....: 0.114610 * foreach_copy....: 0.118020 * foreach_ref.....: 0.000015 * foreach_ref.....: 0.000016 * foreach_ref.....: 0.000016 * foreach_ref.....: 0.000016 * foreach_ref.....: 0.000018 * foreach_ref.....: 0.000019 * foreach_ref.....: 0.000019 * foreach_ref.....: 0.000019 * foreach_ref.....: 0.000019 * foreach_ref.....: 0.000020
Comments
Post a Comment