文档章节

PHP性能分析相关的函数

botkenni
 botkenni
发布于 2016/10/11 11:16
字数 1638
阅读 4
收藏 0

此前,阅读过了很多关于 PHP 性能分析的文章,不过写的都是一条一条的规则,而且,这些规则并没有上下文,也没有明确的实验来体现出这些规则的优势,同时讨论的也侧重于一些语法要点。本文就改变 PHP 性能分析的角度,并通过实例来分析出 PHP 的性能方面需要注意和改进的点。

 

在开始分析之前,我们得掌握一些与性能分析相关的函数。这些函数让我们对程序性能有更好的分析和评测。

 

一、性能分析相关的函数与命令

 

1.1、时间度量函数

 

平时我们常用 time() 函数,但是返回的是秒数,对于某段代码的内部性能分析,到秒的精度是不够的。于是要用 microtime 函数。而 microtime 函数可以返回两种形式,一是字符串的形式,一是浮点数的形式。不过需要注意的是,在缺省的情况下,返回的精度只有4位小数。为了获得更高的精确度,我们需要配置 precision。

 

如下是 microtime 的使用结果。

 

$start= microtime(true);
echo $start."\n";
$end = microtime(true);
echo $end."\n";
echo ($end-$start)."\n";

输出为:

 

bash-3.2# phptime.php

1441360050.3286

1441360050.3292

0.00053000450134277

 

而在代码前面加上一行:

 

    ini_set("precision", 16);

输出为:

 

bash-3.2# phptime.php

1441360210.932628

1441360210.932831

0.0002031326293945312

 

除了 microtime 内部统计之外, 还可以使用 getrusage 来取得用户态的事长。在实际的操作中,也常用 time 命令来计算整个程序的运行时长,通过多次运行或者修改代码后运行,得到不同的时间长度以得到效率上的区别。 具体用法是:time phptime.php ,则在程序运行完成之后,不管是否正常结束退出,都会有相关的统计。

 

bash-3.2# time phptime.php

 

1441360373.150756

1441360373.150959

0.0002031326293945312

 

real 0m0.186s

user 0m0.072s

sys 0m0.077s

 

因为本文所讨论的性能问题,往往分析上百万次调用之后的差距与趋势,为了避免代码中存在一些时间统计代码,后面我们使用 time 命令居多。

 

1.2、内存使用相关函数

 

分析内存使用的函数有两个:memory_ get_ usage、memory_ get_ peak_usage,前者可以获得程序在调用的时间点,即当前所使用的内存,后者可以获得到目前为止高峰时期所使用的内存。所使用的内存以字节为单位。

 

$base_memory= memory_get_usage();
echo "Hello,world!\n";
$end_memory= memory_get_usage();
$peak_memory= memory_get_peak_usage();
echo $base_memory,"\t",$end_memory,"\t",($end_memory-$base_memory),"\t", $peak_memory,"\n";

输出如下:

 

bash-3.2# phphelloworld.php

 

Hello,world!

224400 224568 168 227424

 

可以看到,即使程序中间只输出了一句话,再加上变量存储,也消耗了168个字节的内存。

 

对于同一程序,不同 PHP 版本对内存的使用并不相同,甚至还差别很大。

 

$baseMemory= memory_get_usage();
class User
{
private $uid;
function __construct($uid)
    {
$this->uid= $uid;
    }
}

for($i=0;$i<100000;$i++)
{
$obj= new User($i);
if ( $i% 10000 === 0 )
    {
echo sprintf( '%6d: ', $i), memory_get_usage(), " bytes\n";
    }
}
echo "  peak: ",memory_get_peak_usage(true), " bytes\n";

 

在 PHP 5.2 中,内存使用如下:

 

[root@localhostphpperf]# php52 memory.php

 

0: 93784 bytes

10000: 93784 bytes

…… 80000: 93784 bytes

90000: 93784 bytes

peak: 262144 bytes

 

PHP 5.3 中,内存使用如下

 

[root@localhostphpperf]# phpmemory.php

 

0: 634992 bytes

10000: 634992 bytes

…… 80000: 634992 bytes

90000: 634992 bytes

peak: 786432 bytes

 

可见 PHP 5.3 在内存使用上要粗放了一些。

 

PHP 5.4 - 5.6 差不多,有所优化:

 

[root@localhostphpperf]# php56 memory.php

 

0: 224944 bytes

10000: 224920 bytes

…… 80000: 224920 bytes

90000: 224920 bytes

peak: 262144 bytes

 

而 PHP 7 在少量使用时,高峰内存的使用,增大很多。

 

[root@localhostphpperf]# php7 memory.php

 

0: 353912 bytes

10000: 353912 bytes

…… 80000: 353912 bytes

90000: 353912 bytes

peak: 2097152 bytes

 

从上面也看到,以上所使用的 PHP 都有比较好的垃圾回收机制,10万次初始化,并没有随着对象初始化的增多而增加内存的使用。PHP7 的高峰内存使用最多,达到了接近 2M。

 

下面再来看一个例子,在上面的代码的基础上,我们加上一行,即如下加粗的一行:

 

$obj->self = $obj;

代码如下:

 

$baseMemory= memory_get_usage();
class User
{
private $uid;
function __construct($uid)
    {
$this->uid= $uid;
    }
}

for($i=0;$i<100000;$i++)
{
$obj= new User($i);
$obj->self = $obj;
if ( $i% 5000 === 0 )
    {
echo sprintf( '%6d: ', $i), memory_get_usage(), " bytes\n";
    }
}
echo "  peak: ",memory_get_peak_usage(true), " bytes\n";

 

这时候再来看看内存的使用情况,中间表格主体部分为内存使用量,单位为字节。

图表如下:

 

PHP 5.2 并没有合适的垃圾回收机制,导致内存使用越来越多。而5.3 以后内存回收机制导致内存稳定在一个区间。而也可以看见 PHP7 内存使用最少。把 PHP 5.2 的图形去掉了之后,对比更为明显。

 

 

可见 PHP7 不仅是在算法效率上,有大幅度的提升,在大批量内存使用上也有大幅度的优化(尽管小程序的高峰内存比历史版本所用内存更多)。

 

1.3、垃圾回收相关函数

 

在 PHP 中,内存回收是可以控制的,我们可以显式地关闭或者打开垃圾回收,一种方法是通过修改配置,zend.enable_gc=Off 就可以关掉垃圾回收。缺省情况下是 On 的。另外一种手段是通过 gc _enable()和gc _disable()函数分别打开和关闭垃圾回收。

 

比如在上面的例子的基础上,我们关闭垃圾回收,就可以得到如下数据表格和图表。

 

代码如下:

 

gc_disable();
$baseMemory= memory_get_usage();
class User
{
private $uid;
function __construct($uid)
    {
$this->uid= $uid;
    }
}

for($i=0;$i<100000;$i++)
{
$obj= new User($i);
$obj->self = $obj;
if ( $i% 5000 === 0 )
    {
echo sprintf( '%6d: ', $i), memory_get_usage(), " bytes\n";
    }
}
echo "  peak: ",memory_get_peak_usage(true), " bytes\n";

分别在 PHP 5.3、PHP5.4 、PHP5.5、PHP5.6 、PHP7 下运行,得到如下内存使用统计表。

 

 

图表如下,PHP7 还是内存使用效率最优的。

 

从上面的例子也可以看出来,尽管在第一个例子中,PHP7 的高峰内存使用数是最多的,但是当内存使用得多时,PHP7 的内存优化就体现出来了。

 

这里值得一提的是垃圾回收,尽管会使内存减少,但是会导致速度降低,因为垃圾回收也是需要消耗 CPU 等其他系统资源的。Composer 项目就曾经因为在计算依赖前关闭垃圾回收,带来成倍性能提升,引发广大网友关注。详见:

 

https://github.com/composer/composer/commit/ac676f47f7bbc619678a29deae097b6b0710b799

 

在常见的代码和性能分析中,出了以上三类函数之外,还常使用的有堆栈跟踪函数、输出函数,这里不再赘述。

© 著作权归作者所有

上一篇: PHP 性能分析10则
下一篇: PHP语法性能比较
botkenni
粉丝 20
博文 409
码字总数 434882
作品 0
西城
程序员
私信 提问
深度探讨 PHP 之性能

1.缘起 关于PHP,很多人的直观感觉是PHP是一种灵活的脚本语言,库类丰富,使用简单,安全,非常适合WEB开发,但性能低下。PHP的性能是否真的就 如同大家的感觉一样的差呢?本文就是围绕这么一...

HenryChan
2011/12/01
15.7K
46
收藏好文章 PHP函数的实现原理

作者:HDK (百度) 前言 在任何语言中,函数都是最基本的组成单元。对于php的函数,它具有哪些特点?函数调用是怎么实现的?php函数的性能如何,有什么使用建议?本文将从原理出发进行分析结...

wangtaotao
2010/12/05
0
0
php函数的实现原理及性能分析

前言 在任何语言中,函数都是最基本的技术单元之一。对于php的函数,它具有哪些特点?函数调用是怎么实现?php函数的性能如何,有什么使用建议?本文将从原理出发进行分析结合实际的性能测试...

菜到没谱
2013/10/11
0
5
[转]PHP函数的实现原理及性能分析

作者:HDK (百度) 前言 在任何语言中,函数都是最基本的组成单元。对于php的函数,它具有哪些特点?函数调用是怎么实现的?php函数的性能如何,有什么使用建议?本文将从原理出发进行分析结...

PPP
2012/03/26
0
0
PHP中函数的运行机制与实现原理

PHP中函数的运行机制与实现原理 在任何语言中,函数都是最基本的组成单元。对于php的函数,它具有哪些特点?函数调用是怎么实现的?php函数的性能如何,有什么使用建议?本文将从原理出发进行...

雾渺
2012/05/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

数据库

数据库架构 数据库架构可以分为存储文件系统和程序实例两大块,而程序实例根据不同的功能又可以分为如下小模块。 1550644570798 索引模块 常见的问题有: 为什么要使用索引 什么样的信息能成...

一只小青蛙
今天
5
0
PHP常用经典算法实现

<? //-------------------- // 基本数据结构算法 //-------------------- //二分查找(数组里查找某个元素) function bin_sch($array, $low, $high, $k){ if ( $low <= $high){ $mid = int......

半缘修道半缘君丶
昨天
5
0
GIL 已经被杀死了么?

本文原创并首发于公众号【Python猫】,未经授权,请勿转载。 原文地址:https://mp.weixin.qq.com/s/8KvQemz0SWq2hw-2aBPv2Q 花下猫语: Python 中最广为人诟病的一点,大概就是它的 GIL 了。...

豌豆花下猫
昨天
5
0
git commit message form

commit message一般包括3部分:Header、Body、Footer。 <type>(<scope>):<subject>blank line<body>blank line<footer> header是必需的,body、footer可以省略。 header中type、subject......

ninjaFrog
昨天
5
0
聊聊Elasticsearch的CircuitBreakerService

序 本文主要研究一下Elasticsearch的CircuitBreakerService CircuitBreakerService elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/indices/breaker/CircuitBreakerService.ja......

go4it
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部