奇怪的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静态新闻列表自动生成代码
Jun 14 PHP
php xfocus防注入资料
Apr 27 PHP
PHP中array_map与array_column之间的关系分析
Aug 19 PHP
php中字符查找函数strpos、strrchr与strpbrk用法
Nov 18 PHP
PHP中UNIX时间戳和日期间的转换与计算实例
Nov 19 PHP
PHP之浮点数计算比较以及取整数不准确的解决办法
Jul 29 PHP
php实现中文转数字
Feb 18 PHP
php中的登陆login实例代码
Jun 20 PHP
php使用ftp远程上传文件类(完美解决主从文件同步问题的方法)
Sep 23 PHP
php实现在新浪云中使用imagick生成缩略图并上传的方法
Sep 26 PHP
PHP实现负载均衡下的session共用功能
Apr 17 PHP
laravel框架实现去掉URL中index.php的方法
Oct 12 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
谏山创故乡大分县日田市水坝将设立《进击的巨人》立艾伦、三笠以及阿尔敏的铜像!
2020/03/06 日漫
解析mysql 表中的碎片产生原因以及清理
2013/06/22 PHP
自制基于jQuery的智能提示插件一枚
2011/02/18 Javascript
javascript权威指南 学习笔记之javascript数据类型
2011/09/24 Javascript
javascript面向对象快速入门实例
2015/01/13 Javascript
JS模拟并美化的表单控件完整实例
2015/08/19 Javascript
JavaScript代码实现禁止右键、禁选择、禁粘贴、禁shift、禁ctrl、禁alt
2015/11/17 Javascript
jQuery实现简洁的导航菜单效果
2015/11/23 Javascript
jquery实现刷新随机变化样式特效(tag标签样式)
2017/02/03 Javascript
JavaScript 中Date对象的格式化代码方法汇总
2017/09/06 Javascript
使用jQuery实现两个div中按钮互换位置的实例代码
2017/09/21 jQuery
jQuery Dom元素操作技巧
2018/02/04 jQuery
vue-router3.0版本中 router.push 不能刷新页面的问题
2018/05/10 Javascript
vue+webpack中配置ESLint
2018/11/07 Javascript
jQuery实现的简单日历组件定义与用法示例
2018/12/24 jQuery
详解javascript设计模式三:代理模式
2019/03/25 Javascript
JavaScript实现字符串与HTML格式相互转换
2020/03/17 Javascript
通过实例解析chrome如何在mac环境中安装vue-devtools插件
2020/07/10 Javascript
使用Python生成随机密码的示例分享
2016/02/18 Python
Django接受前端数据的几种方法总结
2016/11/04 Python
浅谈python中列表、字符串、字典的常用操作
2017/09/19 Python
python将.ppm格式图片转换成.jpg格式文件的方法
2018/10/27 Python
Python类的继承、多态及获取对象信息操作详解
2019/02/28 Python
python的pytest框架之命令行参数详解(上)
2019/06/27 Python
Pycharm中import torch报错的快速解决方法
2020/03/05 Python
Python filter()及reduce()函数使用方法解析
2020/09/05 Python
Python常用base64 md5 aes des crc32加密解密方法汇总
2020/11/06 Python
Goodee官方商店:迷你投影仪
2021/03/15 全球购物
C#面试题
2016/05/06 面试题
加拿大留学自荐信
2014/01/28 职场文书
商业活动邀请函
2014/02/04 职场文书
大学社团计划书
2014/05/01 职场文书
2014年党的群众路线教育实践活动整改措施(个人版)
2014/09/25 职场文书
餐饮食品安全责任书
2015/01/29 职场文书
python批量创建变量并赋值操作
2021/06/03 Python
Spring Boot项目如何优雅实现Excel导入与导出功能
2022/06/10 Java/Android