微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

奇怪的PHP引用效率问题分析

函数如下:
<div class="codetitle"><a style="CURSOR: pointer" data="20565" class="copybut" id="copybut20565" onclick="doCopy('code20565')"> 代码如下:

<div class="codebody" id="code20565">
function update_timelist(&$arr,$timestamp,$threshold){
$timequeue = &$arr['timequeue'];
while(!empty($timequeue[0])&&($timestamp-$timequeue[0])>$threshold){
array_shift($timequeue);
}
array_push($timequeue,$timestamp);
if($arr['count']<count($timequeue)){
$arr['count'] = count($timequeue);
}
}

大家看出来这个函数有什么问题了没有?其实,有很大一个问题,就是函数中的: $timequeue = &$arr['timequeue']; 这一行导致程序读入22M数据并生成时间节点链表用了接近40秒,而删掉该行改成直接使用$arr['timequeue']时间就缩短了30秒,只需要10秒左右就处理完了22M。
<div class="codetitle"><a style="CURSOR: pointer" data="12279" class="copybut" id="copybut12279" onclick="doCopy('code12279')"> 代码如下:
<div class="codebody" id="code12279">
function update_timelist(&$arr,$threshold){
while(!empty($arr['timequeue'][0])&&($timestamp-$arr['timequeue'][0])>$threshold){
array_shift($arr['timequeue']);
}
array_push($arr['timequeue'],$timestamp);
if($arr['count']<count($arr['timequeue'])){
$arr['count'] = count($arr['timequeue']);
}

大家看出来是什么问题了吗?问题就count函数上,没有想到吧。PHP将变量指向的真正的内容空间标记为了引用类型和非引用类型,像下面的代码
<div class="codetitle"><a style="CURSOR: pointer" data="90253" class="copybut" id="copybut90253" onclick="doCopy('code90253')"> 代码如下:
<div class="codebody" id="code90253">
$a = 'jb51.cc';
$b = $a;
$c = $b;

实际占用内存空间只有一份,因为PHP的zend引擎使用copy on writing的机制,只在$b,$c修改的时候才会复制一份'jb51.cc'过来,此时'jb51.cc'的内容空间类型为非引用类型,如果改为下面的代码
<div class="codetitle"><a style="CURSOR: pointer" data="29774" class="copybut" id="copybut29774" onclick="doCopy('code29774')"> 代码如下:
<div class="codebody" id="code29774">
$a = 'jb51.cc';
$b = $a;
$c = &$a;

这个会有什么变化?仍然是一份内存空间存放'jb51.cc'吗?不是,因为$c为$a的引用,$a的指向的存储空间需要标记为引用类型,那么必须为$b单独复制一份'jb51.cc'才行了,因为$b指向的是非引用类型。
我们可以这样理解,$c现在是$a的引用了,如果$b仍然执行$a的空间那么修改$c将导致$b也修改,所以此时一旦出现引用即使没有写操作也必须复制一份了。也可以这样理解,PHP对变量指向的内存空间只有非引用和引用两种类型,两种类型不能混合,不能转移。如果什么地方需要改变内存空间的状态则需要copy一份了。
下面就说明为什么多了$timequeue = &$arr['timequeue']会导致count变慢,还记得c函数调用过程吗?实际我们传入的参数需要copy一份拷贝传入,PHP也一样,但是由于copy on writing机制使得count在传入非引用类型时是不会真正copy的,但是$timequeue = &$arr['timequeue']将$timequeue的内存空间指定为了引用类型,而count需要非引用类型,这样就导致count需要copy一份$arr['timequeue']了。直接传入$arr['timequeue']为什么没有问题?count当然是用了copy on writing的机制,array_shift和array_push呢?他们是传入的引用啊,不用担心这不是修改了$arr['timequeue']的类型而是真正的传入了$arr['timequeue']的一个别名。 对于PHP我也是刚刚开始学习,上面的分析不一定正确,也不一定全面。大家可以在我的主页发邮件留言与我交流。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

地址引用效率效率

相关推荐