奇怪的PHP引用效率问题分析
发布时间:2023-10-29 14:36:04
函数如下:
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 = 'aspxhome.com';
$b = $a;
$c = $b;
实际占用内存空间只有一份,因为PHP的zend引擎使用copy on writing的机制,只在$b,$c修改的时候才会复制一份'aspxhome.com'过来,此时'aspxhome.com'的内容空间类型为非引用类型,如果改为下面的代码:
$a = 'aspxhome.com';
$b = $a;
$c = &$a;
这个会有什么变化?仍然是一份内存空间存放'aspxhome.com'吗?不是,因为$c为$a的引用,$a的指向的存储空间需要标记为引用类型,那么必须为$b单独复制一份'aspxhome.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我也是刚刚开始学习,上面的分析不一定正确,也不一定全面。大家可以在我的主页发邮件留言与我交流。


猜你喜欢
- 内容摘要:通常的,ASP中表单提交的数据一般被写入数据库。然而,如果你想让发送数据更为简便易行,那么,可以将它书写为XML文件格式。这种方式
- 学习python编程,首先要配置好环境变量。本文主要讲解python的环境变量配置,在不同版本下如何安装Windows打开Python官方下
- 在使用Python做socket编程时,由于需要使用阻塞(默认)的方式来读取数据流,此时对于数据的结束每次都需要自己处理,太麻烦。并且网上也
- 一、前言Python logging 模块定义了为应用程序和库实现灵活的事件日志记录的函数和类。程序开发过程中,很多程序都有记录日志的需求,
- 最近碰到一个mysql5数据库的问题。就是一个标准的servlet/tomcat网络应用,后台使用mysql数据库。问题是待机一晚上后,第二
- 无法打开用户默认数据库,登录失败,这也是SQL Server使用者熟悉的问题之一。在使用企业管理器、查询分析器、各类工具和应用软件的时候,只
- 假设我们要添加一个我们自己的Middleware,用来记录每次请求的日志下面就是一个符合规范的Middleware, 构造函数中接受一个WS
- 【JS对象属性的查询和设置】可以通过点(.) 或 方括号([]) 运算符来获取属性的值。运算符左侧应当是一个表达式,它返回一个对象。对于点(
- 前言:str转换为json格式,前提一定需要保证这个str的格式和json是一致的,即左边最外层是大括号,右边的最外层是大括号。如果不一致,
- python实现原图裁剪为固定尺寸小图的具体代码,供大家参考,具体内容如下讲解1、代码效果:实现原图裁剪为固定尺寸小图代码import nu
- 概念节流 (throttle) 让一个函数不要执行的太频繁,减少执行过快的调用,叫节流去抖 (debounce) 去抖就是对于一定时间段的连
- 前言当我们使用Python完成自己的原创的工具时,比如:端口扫描、弱口令爆破等。你是否想过添加自己的Logo,以及简要的帮助信息?如下:Sq
- pyfinance简介datasets.py :金融数据下载(基于request进行数据爬虫,有些数据由于外网受限已经无法下载);gener
- 1 引言 在关系数据库(DB2,Oracle,Sybase,Informix和SQL Server)最小的恢复和交易单位为一个事务(Tran
- 按照下面一步一步来,安 * p就是这么简单。脚本之家下载渗透测试软件Burp Suite Professionalhttps://www.jb
- 由于ajax在跨域的访问上有问题,目前最好的方法是做代理.写了个代理程序和心得为了做ajax的代理,研究了下服务器端的xmlhttp并和客户
- 如果你计划将数据库从SQL Server 2000 升级到 SQL Server 2005。你在升级之前一定会测试每样东西,并且证明应用程序
- 前言每条if语句的核心都是一个值为True或False的表达式,这种表达式被称为条件测试。Python根据条件测试的值为True还是Fals
- OCR与Tesseract介绍将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition,OCR)。
- 最近接到一个领导需求,将xmind脑图直接转成可以导入的excel用例,并且转换成gui可执行的exe文件,方便他人使用。因为对Python