奇怪的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 miniBB中文乱码问题解决方法
Nov 25 PHP
PHP Curl出现403错误的解决办法
May 29 PHP
PHP中require和include路径问题详解
Dec 25 PHP
smarty内置函数foreach用法实例
Jan 22 PHP
php表单提交与$_POST实例分析
Jan 26 PHP
PHP简单获取视频预览图的方法
Mar 12 PHP
PHP中preg_match函数正则匹配的字符串长度问题
May 27 PHP
PHP操作MySQL的mysql_fetch_* 函数的常见用法教程
Dec 25 PHP
PHP实现四种基础排序算法的运行时间比较(推荐)
Aug 11 PHP
thinkPHP5.0框架自动加载机制分析
Mar 18 PHP
php中类和对象:静态属性、静态方法
Apr 09 PHP
Yii框架函数简单用法分析
Sep 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函数file_get_contents超时处理的方法详解
2013/06/03 PHP
测试php函数的方法
2013/11/13 PHP
php 5.6版本中编写一个PHP扩展的简单示例
2015/01/20 PHP
微信公众平台实现获取用户OpenID的方法
2015/04/15 PHP
PHP+Apache实现二级域名之间共享cookie的方法
2019/07/24 PHP
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
jQuery的12招常用技巧分享
2011/08/08 Javascript
js获取RadioButtonList的Value/Text及选中值等信息实现代码
2013/03/05 Javascript
将中国标准时间转换成标准格式的代码
2014/03/20 Javascript
遮罩层点击按钮弹出并且具有拖动和关闭效果(两种方法)
2015/08/20 Javascript
JS百度地图搜索悬浮窗功能
2017/01/12 Javascript
Vue打包后出现一些map文件的解决方法
2018/02/13 Javascript
jQuery实现新闻播报滚动及淡入淡出效果示例
2018/03/23 jQuery
如何在Vue中使用CleaveJS格式化你的输入内容
2018/12/14 Javascript
Vue项目打包部署到iis服务器的配置方法
2019/10/14 Javascript
解决vue项目中页面调用数据 在数据加载完毕之前出现undefined问题
2019/11/14 Javascript
详解nginx配置vue h5 history去除#号
2020/11/09 Javascript
[02:36]DOTA2英雄基础教程 斯拉克
2013/11/29 DOTA
Python创建xml的方法
2015/03/10 Python
Python实现快速排序算法及去重的快速排序的简单示例
2016/06/26 Python
人机交互程序 python实现人机对话
2017/11/14 Python
浅谈机器学习需要的了解的十大算法
2017/12/15 Python
详解Python nose单元测试框架的安装与使用
2017/12/20 Python
python如何实现内容写在图片上
2018/03/23 Python
Python检测网络延迟的代码
2018/05/15 Python
Python实现病毒仿真器的方法示例(附demo)
2020/02/19 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
酒店保安员岗位职责
2014/01/31 职场文书
公司授权委托书范本
2014/04/03 职场文书
小班下学期评语
2014/05/04 职场文书
新文化运动的口号
2014/06/21 职场文书
班子成员四风问题自我剖析材料
2014/09/29 职场文书
自荐信怎么写
2015/03/04 职场文书
少年犯观后感
2015/06/11 职场文书
假如给我三天光明读书笔记
2015/06/26 职场文书
小程序实现侧滑删除功能
2022/06/25 Javascript