奇怪的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&amp;mysql(一)
Oct 09 PHP
PHP4 与 MySQL 交互使用
Oct 09 PHP
在IIS上安装PHP4.0正式版
Oct 09 PHP
mysql_fetch_assoc和mysql_fetch_row的功能加起来就是mysql_fetch_array
Jan 15 PHP
修改php.ini实现Mysql导入数据库文件最大限制的修改方法
Dec 11 PHP
php preg_match_all结合str_replace替换内容中所有img
Oct 11 PHP
Discuz 模板语句分析及知识技巧
Aug 21 PHP
基于PHP异步执行的常用方式详解
Jun 03 PHP
php下载文件源代码(强制任意文件格式下载)
May 09 PHP
php图片处理函数获取类型及扩展名实例
Nov 19 PHP
PHP中substr()与explode()函数用法分析
Nov 24 PHP
PDO::_construct讲解
Jan 27 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 根据IP地址控制访问的代码
2010/04/22 PHP
探讨PHP JSON中文乱码的解决方法详解
2013/06/06 PHP
PHP中怎样保持SESSION不过期 原理及方案介绍
2013/08/08 PHP
深入理解PHP变量的值类型和引用类型
2015/10/21 PHP
CodeIgniter框架常见用法工作总结
2017/03/16 PHP
如何快速的呈现我们的网页的技巧整理
2007/07/01 Javascript
自己的js工具_Form 封装
2009/08/21 Javascript
jquery的Tooltip插件 qtip使用详细说明
2010/09/08 Javascript
JqGrid web打印实现代码
2011/05/31 Javascript
NodeJS的模块写法入门(实例代码)
2012/03/07 NodeJs
javascript错误的认识不用关心内存管理
2012/12/15 Javascript
jQuery $.data()方法使用注意细节
2012/12/31 Javascript
解析页面加载与js函数的执行 onload or ready
2013/12/12 Javascript
Javascript实现多彩雪花从天降散落效果的方法
2015/02/02 Javascript
jQuery实现右侧显示可向左滑动展示的深色QQ客服效果代码
2015/10/23 Javascript
详解原生JavaScript实现jQuery中AJAX处理的方法
2016/05/10 Javascript
Node.js中文件操作模块File System的详细介绍
2017/01/05 Javascript
jQuery Collapse1.1.0折叠插件简单使用
2017/08/28 jQuery
jQuery中的for循环var与let的区别
2018/04/21 jQuery
vue-property-decorator用法详解
2019/12/12 Javascript
微信小程序scroll-view点击项自动居中效果的实现
2020/03/25 Javascript
Openlayers实现地图的基本操作
2020/09/28 Javascript
再也不怕 JavaScript 报错了,怎么看怎么处理都在这儿
2020/12/09 Javascript
[02:25]DOTA2英雄基础教程 虚空假面
2014/01/02 DOTA
python爬虫入门教程之糗百图片爬虫代码分享
2014/09/02 Python
Python中的默认参数实例分析
2018/01/29 Python
Python 编程速成(推荐)
2019/04/15 Python
如何基于Python + requests实现发送HTTP请求
2020/01/13 Python
Python使用matplotlib绘制圆形代码实例
2020/05/27 Python
在pycharm创建scrapy项目的实现步骤
2020/12/01 Python
详解CSS3 filter:drop-shadow滤镜与box-shadow区别与应用
2020/08/24 HTML / CSS
英国优质鞋类专家:Robinson’s Shoes
2017/12/08 全球购物
美国儿童玩具、装扮和玩偶商店:Magic Cabin
2018/09/02 全球购物
抽象类和接口的区别
2012/09/19 面试题
小学网上祭英烈活动总结
2014/07/05 职场文书
django注册用邮箱发送验证码的实现
2021/04/18 Python