問題描述
下面是一個大數組的php foreach循環的測試,我認為如果$v
不改變,真正的copy就不會發生,因為copy on write,但為什么按引用傳遞速度很快?
Below is a test of php foreach loop of a big array, I thought that if the $v
don't change, the real copy will not happen because of copy on write, but why it is fast when pass by reference?
代碼 1:
function test1($a){
$c = 0;
foreach($a as $v){ if($v=='xxxxx') ++$c; }
}
function test2(&$a){
$c = 0;
foreach($a as $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 . "
"; //0.03320002555847
echo $end2 - $end1; //0.02147388458252
但這一次,使用傳遞引用很慢.
But this time, using pass by reference is slow.
代碼 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 . "
"; //0.024326801300049
echo $end2 - $end1; //0.037616014480591
誰能解釋一下為什么通過引用傳遞在代碼 1 中很快,而在代碼 2 中卻很慢?
Can someone explain why passing by reference is fast in code1 but slow in code2?
對于代碼 2,主要區別在于 count($a)
,因此循環所用的時間幾乎相同.
With Code 2, the count($a)
makes the main difference, so the time of the loop took is almost the same.
推薦答案
我認為如果
$v
不改變[foreach($a as $v)
],真正的復制不會發生,因為寫入時復制,但為什么按引用傳遞時速度很快?
I thought that if the
$v
don't change [foreach($a as $v)
], the real copy will not happen because of copy on write, but why it is fast when pass by reference?
影響的不是$v
,而是$a
,這個龐大的數組.您可以將它作為值或作為函數的引用傳遞.在函數內部,它是值 (test1) 或引用 (test2).
The impact is not on $v
but on $a
, the huge array. You either pass it as value or as reference to the function. Inside the function it's then value (test1) or reference (test2).
您有兩個代碼(代碼 1 和代碼 2).
You have two codes (code 1 and code 2).
代碼 1: 正在使用 foreach
.使用 foreach
你有兩個選擇:迭代一個值或一個引用(示例).當您迭代一個值時,迭代是在該值的副本上完成的.如果您對引用進行迭代,則不會進行復制.
Code 1: Is using foreach
. With foreach
you've got two options: iterate over a value or a reference (Example). When you iterate over a value, the iteration is done on a copy of the value. If you iterate over a reference, no copy is done.
當您在 test2 中使用參考時,它會更快.不需要復制這些值.但是在 test1 中,您將數組作為值傳遞,該數組會被復制.
As you use the reference in test2, it's faster. The values do not need to be copied. But in test1, you pass the array as value, the array gets copied.
代碼 2: 正在使用 for
.因為在這里實際上什么都不做.在這兩種情況下.您訪問變量并從數組中讀取值.無論是引用還是副本,這幾乎都是一樣的(感謝 PHP 中的寫入時復制優化).
Code 2: Is using for
. For does nothing actually here. In both cases. You access the variable and read value from the array. That's pretty much the same regardless if it's a reference or a copy (thanks to the copy on write optimization in PHP).
您現在可能想知道,為什么代碼 2 中存在 差異.差異不是因為 for
,而是因為 count
.如果你傳遞一個對 count
的引用,PHP 會在內部創建一個它的副本,因為它 count
需要一個副本,而不是一個引用.
You might now wonder, why there is a difference in code 2. The difference is not because of for
but because of count
. If you pass a reference to count
PHP internally creates a copy of it because it count
needs a copy, not a reference.
另請閱讀:請勿使用PHP 參考作者:Johannes Schlüter
Read as well: Do not use PHP references by Johannes Schlüter
我也編譯了一組測試.但我更具體地將代碼放入測試函數中.
I've compiled a set of tests as well. But I more specifically put code into the test functions.
- 空白 - 調用函數有什么區別?
- 計數 -
count
有區別嗎? - For -
for
only (notcount
) 會發生什么? - Foreach - 只是
foreach
- 甚至打破第一個元素.
- Blank - What's the difference in calling the function?
- Count - Does
count
make a difference? - For - What happens with
for
only (notcount
)? - Foreach - Just
foreach
- even breaking on first element.
每個測試都有兩個版本,一個稱為_copy
(將數組作為副本傳遞到函數中)和一個稱為_ref
(將數組作為引用傳遞).
Every test is in two versions, one called _copy
(passing the array as copy into the function) and one called _ref
(passing the array as reference).
這些微基準并不總是告訴你真相,但如果你能夠隔離特定點,你可以很好地進行有根據的猜測,例如不是for
而是count
有影響:
It's not always that these micro-benchmarks tell you the truth, but if you're able to isolate specific points, you can quite well do an educated guess, for example that not for
but count
had the impact:
function blank_copy($a){
}
function blank_ref(&$a){
}
function foreach_copy($a){
foreach($a as $v) break;
}
function foreach_ref(&$a){
foreach($a as $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 as $test)
{
$begin = microtime(true);
for($r=0;$r<$runs;$r++)
$test($x);
$end = microtime(true);
$result = $end - $begin;
printf("* %'.-16s: %f
", $test, $result);
}
}
$buffer = explode("
", ob_get_clean());
sort($buffer);
echo implode("
", $buffer);
輸出:
* 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
這篇關于php foreach,為什么使用數組的引用傳遞很快?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!