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


Posted in PHP onMarch 23, 2012

函数如下:

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。

function update_timelist(&$arr,$timestamp,$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将变量指向的真正的内容空间标记为了引用类型和非引用类型,像下面的代码:
$a = '3water.com'; 
$b = $a; 
$c = $b;

实际占用内存空间只有一份,因为PHP的zend引擎使用copy on writing的机制,只在$b,$c修改的时候才会复制一份'3water.com'过来,此时'3water.com'的内容空间类型为非引用类型,如果改为下面的代码:
$a = '3water.com'; 
$b = $a; 
$c = &$a;

这个会有什么变化?仍然是一份内存空间存放'3water.com'吗?不是,因为$c为$a的引用,$a的指向的存储空间需要标记为引用类型,那么必须为$b单独复制一份'3water.com'才行了,因为$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我也是刚刚开始学习,上面的分析不一定正确,也不一定全面。大家可以在我的主页发邮件留言与我交流。

PHP 相关文章推荐
无数据库的详细域名查询程序PHP版(2)
Oct 09 PHP
php上的memcache和memcached两个pecl库
Mar 29 PHP
PHP的范围解析操作符(::)的含义分析说明
Jul 03 PHP
PHP+MYSQL会员系统的登陆即权限判断实现代码
Sep 23 PHP
百度ping方法使用示例 自动ping百度
Jan 26 PHP
phpmailer在服务器上不能正常发送邮件的解决办法
Jul 08 PHP
Linux下安装oracle客户端并配置php5.3
Oct 12 PHP
CI框架Session.php源码分析
Nov 03 PHP
PHP中使用数组指针函数操作数组示例
Nov 19 PHP
php的闭包(Closure)匿名函数初探
Feb 14 PHP
php截取视频指定帧为图片
May 16 PHP
PHP7新增函数
Mar 09 PHP
php地址引用(php地址引用的效率问题)
Mar 23 #PHP
PHP遍历数组的几种方法
Mar 22 #PHP
php遍历数组的方法分享
Mar 22 #PHP
php中大括号作用介绍
Mar 22 #PHP
那些年一起学习的PHP(三)
Mar 22 #PHP
那些年一起学习的PHP(二)
Mar 21 #PHP
那些年一起学习的PHP(一)
Mar 21 #PHP
You might like
php smarty 二级分类代码和模版循环例子
2011/06/16 PHP
改写函数实现PHP二维/三维数组转字符串
2013/09/13 PHP
PHP读取mssql json数据中文乱码的解决办法
2016/04/11 PHP
php 修改上传文件大小限制实例详解
2016/10/23 PHP
使用 laravel sms 构建短信验证码发送校验功能
2017/11/06 PHP
jquery实现的元素的left增加N像素 鼠标移开会慢慢的移动到原来的位置
2010/03/21 Javascript
用js模拟JQuery的show与hide动画函数代码
2010/09/20 Javascript
javascript使用activex控件的代码
2011/01/27 Javascript
原生JavaScript实现连连看游戏(附源码)
2013/11/05 Javascript
关闭页面时window.location事件未执行的原因分析及解决方案
2014/09/01 Javascript
JavaScript前补零操作实例
2015/03/11 Javascript
JavaScript函数参数使用带参数名的方式赋值传入的方法
2015/03/19 Javascript
javascript实现的字符串与十六进制表示字符串相互转换方法
2015/07/17 Javascript
JavaScript组件开发之输入框加候选框
2017/03/10 Javascript
Vue v2.5 调整和更新不完全问题
2017/10/24 Javascript
vue组件详解之使用slot分发内容
2018/04/09 Javascript
ajaxfileupload.js实现上传文件功能
2019/04/19 Javascript
three.js利用gpu选取物体并计算交点位置的方法示例
2019/11/25 Javascript
JS代码实现页面切换效果
2021/01/10 Javascript
JavaScript实现消消乐的源代码
2021/01/12 Javascript
[04:50]DOTA2亚洲邀请赛小组赛第四日 TOP10精彩集锦
2015/02/02 DOTA
[01:21:07]EG vs Liquid 2018国际邀请赛淘汰赛BO3 第一场 8.25
2018/08/29 DOTA
Python输出PowerPoint(ppt)文件中全部文字信息的方法
2015/04/28 Python
python3使用scrapy生成csv文件代码示例
2017/12/28 Python
对pandas写入读取h5文件的方法详解
2018/12/28 Python
python实现输入的数据在地图上生成热力图效果
2019/12/06 Python
TensorFlow设置日志级别的几种方式小结
2020/02/04 Python
python 日志模块logging的使用场景及示例
2021/01/04 Python
日本著名化妆品零售网站:Cosme Land
2019/03/01 全球购物
2014年乡镇个人工作总结
2014/12/03 职场文书
财务会计岗位职责
2015/02/03 职场文书
大学推普周活动总结
2015/05/07 职场文书
生日赠语
2015/06/23 职场文书
2016年春季趣味运动会开幕词
2016/03/04 职场文书
演讲稿:​快乐,从不抱怨开始!
2019/04/02 职场文书
python模板入门教程之flask Jinja
2022/04/11 Python