奇怪的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 文件状态缓存带来的问题
Dec 14 PHP
PHP大批量数据操作时临时调整内存与执行时间的方法
Apr 20 PHP
php array的学习笔记
May 16 PHP
CodeIgniter图像处理类的深入解析
Jun 17 PHP
php使用mkdir创建多级目录入门例子
May 10 PHP
PHP常量使用的几个需要注意的地方(谨慎使用PHP中的常量)
Sep 12 PHP
今天你说520了吗?不仅有php表白书还有java表白神器
May 20 PHP
PHP 5.6.11中CURL模块问题的解决方法
Aug 08 PHP
利用PHP获取汉字首字母并且分组排序详解
Oct 22 PHP
php进程daemon化的正确实现方法
Sep 06 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
Nov 14 PHP
PHP使用PDO实现mysql防注入功能详解
Dec 20 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
从零开始 教你如何搭建Discuz!4.1论坛
2006/07/07 PHP
PHP简单系统数据添加以及数据删除模块源文件下载
2008/06/07 PHP
PHP与SQL注入攻击防范小技巧
2011/09/16 PHP
PHP中extract()函数的妙用分析
2012/07/11 PHP
ThinkPHP关于session的操作方法汇总
2014/07/18 PHP
php读取flash文件高宽帧数背景颜色的方法
2015/01/06 PHP
在Mac OS上自行编译安装Apache服务器和PHP解释器
2015/12/24 PHP
PHP反射机制原理与用法详解
2017/02/15 PHP
php设计模式之模板模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
tp5框架前台无限极导航菜单类实现方法分析
2020/03/29 PHP
CSS中一些@规则的用法小结
2021/03/09 HTML / CSS
IE下使用cloneNode注意事项分享
2012/11/22 Javascript
18个非常棒的jQuery代码片段
2015/11/02 Javascript
jquery实现文本框textarea自适应高度
2016/03/09 Javascript
js浏览器html5表单验证
2016/10/17 Javascript
微信小程序 石头剪刀布实例代码
2017/01/04 Javascript
vue bootstrap小例子一枚
2017/06/09 Javascript
详解webpack介绍&amp;安装&amp;常用命令
2017/06/29 Javascript
解析Vue 2.5的Diff算法
2017/11/28 Javascript
微信小程序数字滚动插件使用详解
2018/02/02 Javascript
Angular angular-file-upload文件上传的示例代码
2018/08/23 Javascript
nodejs对mongodb数据库的增加修删该查实例代码
2020/01/05 NodeJs
vue自定义标签和单页面多路由的实现代码
2020/05/03 Javascript
[02:02]DOTA2英雄基础教程 斯拉达
2013/12/11 DOTA
python挖矿算力测试程序详解
2019/07/03 Python
Python修改列表值问题解决方案
2020/03/06 Python
python中return如何写
2020/06/18 Python
利用keras使用神经网络预测销量操作
2020/07/07 Python
Python将QQ聊天记录生成词云的示例代码
2021/02/10 Python
使用css实现android系统的loading加载动画
2019/07/25 HTML / CSS
白宫黑市官网:White House Black Market
2016/11/17 全球购物
澳大利亚儿童和婴儿产品在线商店:Lime Tree Kids
2017/10/05 全球购物
2014教师党员个人自我评议
2014/09/20 职场文书
群众路线对照检查剖析材料
2014/10/09 职场文书
工作年限证明模板
2014/11/01 职场文书
一文弄懂MySQL索引创建原则
2022/02/28 MySQL