PHP 性能分析与实验——性能的宏观分析

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

对 PHP 性能的分析,咱们从两个层面着手,把这篇文章也分红了两个部分,一个是宏观层面,所谓宏观层面,就是 PHP 语言自己和环境层面,一个是应用层面,就是语法和使用规则的层面,不过不只探讨规则,更辅助以示例的分析。算法

宏观层面,也就是对 PHP 语言自己的性能分析又分为三个方面:

PHP 做为解释性语言性能有其自然的缺陷编程

PHP 做为动态类型语言在性能上也有提高的空间缓存

当下主流 PHP 版本自己语言引擎性能性能优化

1、PHP 做为解释性语言的性能分析与提高

PHP 做为一门脚本语言,也是解释性语言,是其自然性能受限的缘由,由于同编译型语言在运行以前编译成二进制代码不一样,解释性语言在每一次运行都面对原始脚本的输入、解析、编译,而后执行。以下是 PHP 做为解释性语言的执行过程。
图片描述服务器

如上所示,从上图能够看到,每一次运行,都须要经历三个解析、编译、运行三个过程。并发

那优化的点在哪里呢?能够想见,只要代码文件肯定,解析到编译这一步都是肯定的,由于文件已再也不变化,而执行,则因为输入参数的不一样而不一样。在性能优化的世界里,至上绝招就是在得到一样结果的状况下,减小操做,这就是大名鼎鼎的缓存。缓存无处不在,缓存也是性能优化的杀手锏。因而乎 OpCode 缓存这一招就出现了,只有第一次须要解析和编译,而在后面的执行中,直接由脚本到 Opcode,从而实现了性能提速。执行流程以下图所示:框架

图片描述

相对每一次解析、编译,读到脚本以后,直接从缓存读取字节码的效率会有大幅度的提高,提高幅度到底有多大呢?编程语言

咱们来作一个没有 Opcode 缓存的实验。20 个并发,总共 10000 次请求没有通过 opcode 缓存的请求,,获得以下结果:
图片描述函数

其次,咱们在服务器上打开 Opcode 缓存。要想实现 opcode 缓存,只须要安装 APC、Zend OPCache、eAccelerator 扩展便可,即便安装了多个,也只启用其中一个。注意的是,修改了 php.ini 配置以后,须要从新加载 php-fpm 的配置。

这里分别启用 APC 和 Zend OPCache 作实验。启用 APC 的版本。
图片描述

能够看到,速度有了较大幅度的提高,原来每一个请求 110ms,每秒处理请求 182 个,启用了 APC 以后 68ms,每秒处理请求 294 个,提高速度将近 40%。

在启用了 Zend Opcache 的版本中,获得同 APC 大体至关的结果。每秒处理请求 291 个,每请求耗时 68.5ms。
图片描述

从上面的这个实验能够看到,所用的测试页面,有 40ms 以上的时间花在了语法解析和编译这两项上。经过将这两个操做缓存,能够将这个处理过程的速度大大提高。

这里附加补充一下,OpCode 究竟是什么东东,OpCode 编译以后的字节码,咱们可使用bytekit 这样的工具,或者使用 vld PHP 扩展来实现对 PHP 的代码编译。以下是 vld 插件解析代码的运行结果。
图片描述
能够看到每一行代码被编译成相应的 OpCode 的输出。

2、PHP 做为动态类型语言的性能分析与改进

第二个是 PHP 语言是动态类型的语言,动态类型的语言自己因为涉及到在内存中的类型推断,好比在 PHP 中,两个整数相加,咱们能获得整数值,一个整数和一个字符串相加,甚至两个字符串相加,都变成整数相加。而字符串和任何类型链接操做都成了字符串。

$a = 10.11;

$b = "30";

var_dump($a+$b);

var_dump("10"+$b);

var_dump(10+"20");

var_dump("10"+"20");

运行结果以下:

float(40.11)

int(40)

int(30)

int(30)

语言的动态类型为开发者提供了方便,语言自己则会由于动态类型而下降效率。在 Swift 中,有一个特性叫类型推断,咱们能够看看类型推断会带来多大的一个效率上的差异呢?对于须要类型推断与不须要类型推断两段 Swift 代码,咱们尝试编译一下看看效果如何。 第一段代码以下:
图片描述

这是一段 Swift 代码,字典只有 14 个键值对,这段代码的编译,9 分钟了尚未编译完成(5G 内存,2.4GHz CPU),编译环境为 Swift 1.2,Xcode 6.4。
图片描述

可是若是调整代码以下:
图片描述
也就是加上了类型限定,避免了 planeLocation 的类型推断。编译过程花了 2S 。
图片描述
可见,做为动态类型附加的类型推断操做极大地下降了程序的编译速度。 固然,这个例子有点极端,用 Swift 来类比 PHP 也不必定合适,由于 Swift 语言自己也还在不断的进化过程当中。本例子只是代表在编程语言中,若是是动态类型语言,就涉及到对动态类型的处理,从编译的角度讲是会受影响的。

那么做为动态类型的 PHP 的效率如何提高呢?从 PHP 语言自己这个层面是没有办法解决的,由于你怎么写也是动态类型的代码。解决办法就是将PHP转化为静态类型的表示,也就是作成扩展,能够看到,鸟哥的不少项目,好比 Yaf 框架,都是作成了扩展的,固然这也是因为鸟哥是 C 高手。扩展因为是 C 或者 C++ 而写,因此再也不是动态类型,又加之是编译好的,而 C 语言自己的效率也会提高不少。因此效率会大幅度提升。

下面咱们来看一段代码,这段代码,只是实现了简单的素数运算,能计算指定值之内的素数个数,用的是普通的筛选法。如今看看扩展实现,跟 PHP 原生实现的效率差异,这个差异固然,不只仅是动态类型和编译类型的差异,还有语言效率的差异。

首先是用纯 PHP 写成的算法,计算 1000 万之内的素数个数,耗时在 33s 上下,实验了三次,获得的结果基本相同。
图片描述
其次,咱们将这个求素数个数的过程,编写成了 PHP 扩展,在扩展中实现了 getprimenumbers 函数,输入一个整数,返回小于该整数的素数。获得的结果以下,这个效率的提高是很是惊人的,在 1.4s 上下即返回。速度提高 20 倍以上。
图片描述
能够想见,静态和编译类型的语言,其效率获得了惊人的提高。本程序的 C 语言代码以下:

PHP_FUNCTION(get_prime_numbers)

{

long value;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) {

return;

}

int *numbers = (int *)malloc(sizeof(int)*128*10000);

memset(numbers, 0x0, 128*10000);

int num = 2;

numbers[0] = 2;

numbers[1] = 3;

bool flag = true;

double f = 0;

int i = 0;

int j = 0;

for(i=5; i<=value; i+=2)

{

flag = true;

f = sqrt(i);

for(j=0; j

{

if(i%numbers[j]==0)

{

flag = false;

break;

}

if(numbers[j]>f)

{

break;

}

}

if(flag)

{

numbers[num] = i;

num++;

}

}

free(numbers);

RETURN_LONG(num);

}

3、PHP 语言自己底层性能引擎提高

第三个性能优化层面是语言自己的性能提高,这个就不是咱们普通开发者所能作的了。在 PHP 7之前,寄但愿于小版本的改进,可是改进幅度不是很是的显著,好比 PHP 5.3 、PHP 5.四、PHP 5.五、PHP 5.5 对同一段代码的性能比较,有必定程度的进步。

PHP 5.3 的版本在上面的例子中已讲过,须要 33s 左右的时间,咱们如今来看别的PHP版本。分别运行以下:

PHP 5.4 版,相较 5.3 版已经有必定程度的提高。快 6 秒左右。
图片描述

PHP 5.5 版在 PHP 5.4的基础上又进了一步,快了 6S。
![图片描述][15]
PHP5.6 反而有些退步。
图片描述

PHP 7 果然是效率提高惊人,是 PHP5.3 的 3 倍以上。
图片描述

以上是求素数脚本在各个 PHP 版本之间的运行速度区别,尽管只测试了这一个程序,也不是特别的严谨,可是这是在同一台机器上,并且编译 configure 参数也基本同样,仍是有必定可比性的。

在宏观层面,除了上面的这些以外,在实际的部署过程当中,对PHP 性能的优化,还体现为要减小在运行中所消耗的资源。因此 FastCGI 模式和 mod_php 的模式比传统的 CGI 模式也更为受欢迎。由于在传统的 CGI 模式中,在每一次脚本运行都须要加载全部的模块。而在程序运行完成了以后,也要释放模块资源。以下图所示:
![图片描述][19]
而在 FastCGI 和 mod_php 模式中,则不须要如此。只有 php-fpm 或者 Apache 启动的时候,须要加载一次全部的模块,在具体的某次运行过程当中,并不须要再次加载和释放相关的模块资源。
图片描述

这样程序性能的效率获得了提高。以上就是有关 PHP 宏观层面的性能优化的分析,在本文的第二部分咱们将探讨应用方面的 PHP 优化准则。敬请期待!

相关文章
相关标签/搜索