加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php foreach,为什么使用数组引用传递速度快?

发布时间:2020-12-13 13:26:53 所属栏目:PHP教程 来源:网络整理
导读:下面是对一个大数组的php foreach循环的测试,我认为如果$v不改变,真正的副本不会因为写入时的副本而发生,但为什么它通过引用传递时速度快? 代码1: function test1($a){ $c = 0; foreach($a as $v){ if($v=='xxxxx') ++$c; }}function test2($a){ $c = 0; f
下面是对一个大数组的php foreach循环的测试,我认为如果$v不改变,真正的副本不会因为写入时的副本而发生,但为什么它通过引用传递时速度快?

代码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 . "n";   //0.03320002555847
echo $end2 - $end1;           //0.02147388458252

但这一次,使用pass by reference很慢.

代码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,'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

有人可以解释为什么通过引用传递在code1中速度快但在code2中速度慢吗?

编辑:
使用代码2,计数($a)产生主要差异,因此循环所用的时间几乎相同.

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).

你有两个代码(代码1和代码2).

代码1:正在使用foreach.使用foreach,您有两个选择:迭代值或引用(Example).迭代值时,迭代将在值的副本上完成.如果迭代引用,则不会执行任何复制.

当您在test2中使用引用时,它会更快.不需要复制值.但是在test1中,您将数组作为值传递,数组将被复制.

代码2:正在使用.因为这里什么也没做.在这两种情况下.您可以从数组中访问变量和读取值.无论是引用还是副本(这要归功于PHP中的写入优化副本),这几乎是一样的.

您现在可能想知道,为什么代码2存在差异.差异不是因为for而是因为计数.如果你传递一个引用计数PHP内部创建它的副本,因为它计数需要一个副本,而不是一个引用.

阅读:Do not use PHP references by Johannes Schlüter

我也编译了一组测试.但我更具体地将代码放入测试函数中.

>空白 – 调用函数有什么区别?
>伯爵 – 伯爵会有所作为吗?
>对于 – foronly(不计数)会发生什么?
> Foreach – Just foreach – 甚至打破第一个元素.

每个测试都有两个版本,一个名为_copy(将数组作为副本传递给函数),另一个名为_ref(将数组作为参考传递).

并不总是这些微基准测试告诉你真相,但如果你能够隔离特定点,你可以很好地做出有根据的猜测,例如,不是因为计数产生了影响:

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,'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: %fn",$test,$result);
    }
}

$buffer = explode("n",ob_get_clean());
sort($buffer);
echo implode("n",$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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读