http://www.laruence.com/2016/12/18/3137.html
**本文是最初是来自国外的这篇:[PHP Performance Evolution 2016](https://www.phpclasses.org/blog/post/493-php-performance-evolution.html), 感谢高可用架构公众号翻译成了中文版, 此处是转载的高可用架构翻译后的文章[从PHP 5到PHP 7性能全评测(含未发布的JIT版PHP 8对比)](http://weibo.com/ttarticle/p/show?id=2309404052280251914593), 稍微调整了格式而成。
**
*导读:PHP 是 Web 开发最常用的语言,每个大版本的更新都带来不少新特性和性能提升。特别是 PHP 7.0 的发布,带来 PHP 性能飞跃。本文作者对各个 PHP 版本进行了 CPU 性能基准测试,并且带来了PHP下个大版本的消息。本文中文版由高可用架构志愿者翻译。*
自 1994 年 Rasmus Lerdorf 创建 PHP 以来, PHP 语言经历了许多改进,其中性能是开发人员在评估新版本时考虑的主要标准之一。
阅读这篇文章,可以了解从 PHP 5 到 7(包括 7.1)的性能提升,同时也将了解到即将加入到 PHP 8 的试验性的 JIT 分支版本的性能。
### 简介
本文将根据时间作出更新,增加更多信息和基准测试结果,包括尚未发布的新版本,以便更好地了解多年来 PHP 性能演变。如果您有更正或建议改进,请在文后留言。
自 1994 年 Rasmus Lerdorf 创建 PHP 以来, PHP 语言经历了激烈的演进。虽然第一版是一个简单的一人开发的 CGI 程序,Rasmus Lerdorf、Andi Gutmans 和 Zeev Suraski 加入了该语言的第三个版本的开发,并根本性重新设计。从那之后, PHP 开发组也创建并发展起来。
随着项目的发展,由于 PHP 3 天然的可扩展性, PHP 在核心和附加扩展开发的功能得到了蓬勃发展,如网络通信,解析,缓存和数据库支持。
语言本身也在发展,带来了一系列的改进。这包括支持面向对象的结构,例如类,接口, traits,闭包等。
对于许多开发人员来说,仅有新功能是不够的。随着语言越来越受欢迎, PHP 社区对于提供更好性能,可扩展性和更少内存使用的需求越来越强烈。
PHP 开发团队近 20 年来一直致力于解决这些需求,虽然 PHP 3 的引入大大提高了性能,但直到 Andi Gutmans 和 Zeev Suraski 引入 Zend Engine 并发布 PHP 4, PHP 的性能才开始变得正式起来。
2000 年推出的新的内存编译器和执行器模型大大提高了 PHP 的性能(提高了 5 倍甚至 10 倍),并首次被正式的 Web 应用程序和站点所使用。我们可以说,今天 PHP 的成果远远超出了任何人在 PHP 项目诞生时的期望。
PHP 的蓬勃发展增加了改善性能的欲望。幸运的是, Zend Engine 中设计的模型为持续优化性能提供了良好的基础。
虽然 PHP 5.0 没有带来实质性的性能提升,并且在某些情况下甚至比 PHP4 更慢,一个由 Dmitry Stogov 领导的团队在社区的大力帮助下已经在后续版本中不断优化语言,在 PHP 5.6 发布的时候,在大多数情况下,性能提升在 1.5x 和 3x 之间。
2015 年 12 月, PHP 7.0 取得了重大突破。 2016 年 12 月,7.1 版本也带来了一系列增强功能。
### PHP 8 性能展望
这是一个前途光明的版本,目前正在开发当中,由 Zend 的 Dmitry Stogov 主导。虽然它是基于 PHP 7.1 版本基础,但实际版本号尚未定义,所以本文称这个版本为“试验 JIT”分支下。
关键功能 JIT(Just-In-Time)编译,是一种将代码转换为另一种字节码(比如运行它的机器 CPU 的本地代码)的技术。 JIT 可以使程序运行更快。
本文涵盖了几个基准测试的结果,从 PHP 5 的第一个版本到 PHP 的试验性 JIT 分支版本,PHP 5 之前的版本性能本文不作介绍。
在写这篇文章的时候,我们很难确定 PHP 8 之前是否会有另一个主要版本,比如 PHP 7.2。但是可以假设在 PHP 8 发布时,它已经包括当前试验版 JIT 分支的强大功能。
### PHP 性能评估
本文只运行纯 CPU 任务脚本的基准测试(不需要I / O操作的任务例如访问文件,网络或数据库连接)。
使用的基准测试脚本如下所示:
~~~
bench.php 可在PHP源代码的 php-src/Zend 目录micro_bench.php 也可以在 PHP 源代码发布的 php-src/Zend 目录中找到mandelbrot.php https://gist.githubusercontent.com/dstogov/12323ad13d3240aee8f1/raw/37fed3beb7e666b70e199bcf361af541b3c30d2d/b.php
~~~
基准脚本仅使用每个PHP主要版本的最新小版本运行。因此,测试的版本如下:
~~~
5.0.55.1.65.2.175.3.295.4.455.5.385.6.287.0.137.1.0PHP-JIT(JIT实验分支)
~~~
当然,我想确定,我们在相同的基准上运行所有小版本,例如在 5.3.0 到 5.3.29 之间。结果是有说服力的:性能方面的主要增强不是由小版本带来的,而是主要版本号的变化,例如从 PHP 5.4 到 PHP 5.5,或从PHP 5.6 到 PHP 7。
小版本没有显示任何明显的性能改进。这意味着相同的脚本应该以相同的速度运行,无论您使用 PHP 5.4.0 还是 PHP 5.4.45。
您可以查看基准进程部分,详细说明主机系统的设置,各个基准的运行方式以及如何解释时序结果。
### 纯 CPU 基准测试结果
这部分给出了每个 PHP 版本的基准测试结果。
每个基准列显示 3 个值:
* 时间: 执行时间,以秒和毫秒为单位
* %rel, gain:相对于以前的版本收益的执行时间。 在下面的表格中,例如,%rel。 bench.php 和版本 5.3.29 的收益是 31.89%,意味着该脚本比 5.2.17 版本运行快 31.89%。
* %abs, gain:与 PHP 5.0 相比脚本运行的收益。 如果你看看bench.php 和试验性的 JIT 分支的这个列的交集,你会注意到,对于这个特定的测试基准,PHP 8 比 PHP 5.0 快 41 倍以上。
纯CPU基准测试的结果如下所示:
[](http://laruence-blog.stor.sinaapp.com/uploads/2016/12/img.jpg)
CPU基准测试
*
(1)测试不能在 5.3 之前的版本上运行,因为它使用了尚未实现的对象功能。
(2)此列中的结果有点偏颇,因为基准需要至少 PHP 5.3 运行。把它们当成纯粹说明,因为他们不能与 PHP 5.0 性能进行比较。
(3)这是一个 mandelbrot.php 脚本的修改版本,它运行得太快,在 7.1.0 和试验 JIT 分支无法准确的统计时间,我们在脚本中运行计算 100 次而不是 1 次。
*
[](http://laruence-blog.stor.sinaapp.com/uploads/2016/12/img1.jpg)
当然,这些都是纯 CPU 的基准测试。它们不涵盖 PHP 性能的所有方面,它们可能不代表真实情况。但是结果足够显著,足以说明几个方面的问题:
* PHP 5.1 将 PHP 5.0的 性能提高了一倍多
* 5.2 和 5.3 带来了他们自己的一些性能增强,但他们没有像5.1版本那样引人注目。
* 5.4 版本是一个大的性能改进。(这里有我曾经分享过的PHP5.4的性能优化的演讲PPT[PHP-5.4 Performance](http://www.slideshare.net/laruence/php-54-performance))
* opcache 扩展插件与 5.5 和 5.6 版捆绑在一起。当相同的脚本在 Web 服务器连续运行时,由于更快的代码加载会带来性能增强。但是,opcache 不会真正显示其在CLI模式下执行脚本的优势。
* PHP 7.0 是性能方面的一个重大突破。 Zend Engine 已经完全重新设计,我们可以在这里看到这项工作的结果。(这里有我曾经分享过的PHP7的性能优化的演讲的PPT[The secret of PHP7’s Performance](http://www.slideshare.net/laruence/the-secret-of-php7s-performance))
* PHP 7.1 在 opcache 扩展中引入了 opcode 优化。这再次解释了上述表格中当与 7.0 相比时,性能的增益。(这里有我曾经分享过的PHP7.1的性能优化的演讲PPT[PHP 7.1’s New Features and Performance](http://www.slideshare.net/laruence/php71-new-features-performance)
* 试验 JIT 分支是另一个重大突破,JIT 可以对现有代码提供很大的性能改进,但在某些情况下,你可能会注意到速度提高只有几个百分点,在最坏的情况下,它甚至可能会变慢,因为编译不会生成更快的代码。请记住,此功能目前正在开发中。
本节介绍了 3 个纯 CPU 基准测试脚本的结果。在运行通常执行的以数据库或文件访问典型场景的 PHP 应用程序时,它不会给出同样的数字,但我认为他们能够代表您对代码的某些部分期望的性能改进。
### PHP 每个版本的性能提升
PHP 5 相比 PHP 4 带来了明显的改进。 Zend Engine 是 PHP 解释器的核心,它已经完全重新设计( Zend Engine 2),为将来的增强功能奠定了基础。本文不多介绍 PHP 4 和 PHP 5 之间的差异,只简要概述的 PHP 5.0 之后发生了什么。
以下部分列出了在后续 PHP 版本中的改进。请注意,这里仅列出影响 PHP 核心的修改。有关更完整的描述,请查看 PHP 5 和 PHP 7 的change log。
PHP 5.1
* Compiled variables
* Specialized executor
* Real-path cache
* Faster switch() statement handling
* Faster array functions
* Faster variable fetches
* Faster magic method invocations
PHP 5.2
* New memory manager
* Optimized array/HashTable copying
* Optimized require\_once() and include\_once() statements
* Small optimization on specific internal functions
* Improved compilation of HEREDOCS and compilation of interpolated strings
PHP 5.3
* Segmented VM stack
* Stackless VM
* Compile-time constants substitution
* Lazy symbol table initialization
* Real-path cache improvement
* Improved PHP runtime speed and memory usage
* Faster language parsing
* Improved PHP binary size and code startup
PHP 5.4
* Delayed HashTable allocation
* Constant tables
* Run-Time binding caches
* Interned Strings
* Improved the output layer
* Improved ternary operator performance when using arrays
PHP 5.5
* Improved VM calling convention
* OPcache integration
* Other misc. optimizations to the Zend Engine
PHP 5.6
* Optimized empty string handling, minimizing the need to allocate new empty values
PHP 7.0
下面大部分列出的改进都与 Zend Engine 相关:
* Core data structures re-factoring
* Better VM calling convention
* New parameters parsing API
* Yet another new memory manager
* Many improvements in VM executor
* Significantly reduced memory usage
* Improved \_\_call() and \_\_callStatic() functions
* Improved string concatenation
* Improved character searching in strings
PHP 7.1
* New SSA based optimization framework (embedded into opcache)
* Global optimization of PHP bytecode based on type inference
* Highly specialized VM opcode handlers
PHP 8 / 下一代试验性 JIT 分支版
* Just-In-Time compiling
### 性能如何衡量
基准化比单纯运行 Unix 时间命令来测量脚本的执行有所区别。 这就是为什么我经历了以下步骤:
#### 配置系统
首先我设置了一个具有以下特性的专用系统:
* 一个带有1个2.4GHz虚拟内核,2GB RAM和两个SSD驱动器的VPS,一个用于存储操作系统数据,另一个用于存储各种PHPyuan dai ma,二进制文件和报告输出
* Debian Wheezy操作系统,版本3.2.82-1
* Gnu C编译器版本4.9.2-10(Debian Jessie发行版)
* *虽然系统捆绑了Gnu C编译器版本4.7.2,但需要升级到更新的版本。 试验性 JIT 分支必须用Gnu C> = 4.8编译。*
#### 编译源代码
在构建完整发行版之前,使用以下选项运行配置脚本:
~~~
--prefix=/usr/local/php--disable-debug--disable-phpdbg--enable-mysqlnd--enable-bcmath--with-bz2=/usr--enable-calendar--with-curl--enable-exif--enable-fpm--with-freetype-dir--enable-ftp--with-gd--enable-gd-jis-conv--enable-gd-native-ttf--with-gettext=/usr--with-gmp--with-iconv--enable-intl--with-jpeg-dir--enable-mbstring--with-mcrypt--with-openssl--enable-pcntl--with-pdo-mysql=mysqlnd--with-png-dir--with-recode=/usr--enable-shmop--enable-soap--enable-sockets--enable-sysvmsg--enable-sysvsem--enable-sysvshm--enable-wddx--with-xmlrpc--with-xsl--with-zlib=/usr--enable-zip--with-mysqli=mysqlnd
~~~
注意,在编译旧版时,上面的一些选项需要被禁用或被其他替代,并且并不是所有的扩展都可用或可以被编译。
#### 运行基准测试
每个基准测试都使用 PHP CLI 专用脚本运行,该脚本遵循以下步骤:
使用 microtime()函数从内部获取脚本执行时间。 在此修改后,基准脚本将如下所示:
~~~
<?php $__start__ = microtime( true ); /*** original benchmark script code here ***/ fprintf( STDERR, microtime( true ) - $__start__); ?>
~~~
执行 2 次运行,以确保 PHP 可执行文件和基准测试脚本内容都在操作系统缓存中
运行脚本 5 次,并提取最小,最大和平均运行时间,如脚本报告。 本文仅显示平均运行时间,称之为“脚本运行时间”。
php.ini 文件如下所示:
~~~
engine = Onshort_open_tag = Offrealpath_cache_size = 2Mmax_execution_time = 86400memory_limit = 1024Merror_reporting = 0display_errors = 0display_startup_errors = 0log_errors = 0default_charset = "UTF-8" [opcache]zend_extension=opcache.soopcache.enable=1opcache.enable_cli=1opcache.optimization_level=-1opcache.fast_shutdown=1opcache.validate_timestamps=1opcache.revalidate_freq=60opcache.use_cwd=1opcache.max_accelerated_files=100000opcache.max_wasted_percentage=5opcache.memory_consumption=128opcache.consistency_checks=0opcache.huge_code_pages=1 // PHP 8/Next onlyopcache.jit=35opcache.jit_buffer_size=32M
~~~
#### 分析运行结果
使用 Unix time 命令来计时,输出如下所示:
~~~
$ time php bench.phpreal: 0m1.96suser: 0m1.912ssys: 0m0.044s
~~~
第一个值,real : 是命令开始到终止之间的时间(当你回到 shell 提示符)。
第二个值,user :说明在用户模式中花费的时间(在我们的例子中,这是在 php 可执行文件中花费的时间)。
最后一个值 sys :说明在操作系统(内核)调用中花费的时间。这个值应该是最小的,但是如果你的代码访问缓慢的设备结果会比较大。重负载的操作系统也可能影响此处报告的值。
在空闲系统上通常,数量(user + sys)应该非常接近 real。这是在上面的例子中的情况:user + sys = 1.956s,real 是 1.960s。 0.004s 的差异不属于当前进程:它仅仅意味着操作系统执行任务所花费的额外时间,例如调度。
同一个脚本在一个负载很重的系统上执行,并行编译 3 个不同的 PHP 版本:
~~~
$ time php bench.phpreal: 0m7.812suser: 0m2.02ssys: 0m0.101s
~~~
在这里我清楚地看到,系统本身的重负载对使用的时间(也许在系统时间)有重大影响。
这就是为什么我在这个基准中保留一个额外的值,操作系统开销,这是调用的时间和(用户+系统)时间之间的差。
在纯 CPU 基准测试活动期间,我确保在 99% 以上的时间,这个值严格小于 100 毫秒,即使运行需要几十秒钟完成的脚本。
### 特别鸣谢
特别鸣谢 Dmitry Stogov 和所有 PHP 核心开发者们。
本文是和 Dmitry Stogov 合作完成的 , 他帮助审阅了文章内容 , 来保证这个文章的正确性。
Dmitry Stogov 曾经是 Truck MMCache 的开发者,在 PHP4 时代就可以用作共享内存中缓存 PHP Opcode,从那时候起,Dmitry Stogov 就加入了 Zend,一直到现在。
Dmitry 是 PHP NG 的主要开发者 , 也就是我们后来知道的 PHP7, 和 Dmitry 一起合作的有 Xinchen Hui(就是我 :)),Nikita Popov,正是他们在一起开发了 PHP7 以及后来的版本包括 PHP JIT。
在 PHP7 之前 , PHP5 时代的 Andi Gumans, Zeev Suraski 以及 Stas Malishev 等也做了很多的工作来提升 PHP5 的性能,限于篇幅,本文就不详细介绍。
### 结论
本文的目的是给你一个不同版本PHP性能的概述,从 5.0 开始,到当前正在开发的最新版本,使用一组已知的基准脚本。
它还为您提供了由每个连续 PHP 版本解决的性能改进方面的列表。
本文将随着新的 PHP 版本的公布而更新,并且将来会添加新的基准测试结果。 我也希望添加一些真实世界的 PHP 应用程序,如 WordPress 的基准测试结果。
如果您有任何问题或发现不准确,请随时发表评论。 同时,与其他对 PHP 性能感兴趣的开发人员分享这篇文章。
- 程序优化
- vtune
- linux性能监控软件Perf
- 系统级性能分析工具perf的介绍与使用
- perf的二级命令
- 全局性概况
- 全局细节
- 最常用功能perf record
- 可视化工具perf timechart
- perf引入的overhead
- perf stat
- gprof
- 三种Linux性能分析工具的比较
- perf+gprof+gprof2dot+graphviz进行性能分析热点
- 英特尔多核平台编程优化大赛报告
- 内存操作
- mmap
- mmap的分类
- 深入理解内存映射mmap
- 计算机底层知识拾遗(九)深入理解内存映射mmap
- 内核驱动mmap Handler利用技术(一)
- Windows内存管理机制及C++内存分配实例
- Linux内存管理初探
- Windows CPU信息查看
- Linux CPU信息查看
- 预留大内存
- Linux下试验大页面映射
- /dev/mem
- Linux中通过/dev/mem操控物理地址
- /dev/mem分析
- 用法举例
- Linux下直接读写物理地址内存
- 查看内存信息
- Cache Memory
- 页面缓存
- 查看各级cache信息的方法
- dmidecode命令查看cache size
- CPU Cache 机制以及 Cache miss
- ARM体系关闭mmu和cache
- CR0-4寄存器介绍
- 查看CR0,CR2,CR3的值
- Linux 下如何禁用CPU cache
- 7个示例科普CPU Cache
- 第一个例子的C代码
- 其中之一
- Linux 从虚拟地址到物理地址
- 内存测试例子
- 每个程序员都应该了解的内存
- Part 1
- 程序员能够做什么
- 3 CPU caches
- 6 What Programmers Can Do
- VirtualAlloc
- Large-Page Support
- Some remarks on VirtualAlloc and MEM_LARGE_PAGES
- DMA
- MOV和MOVS的效率问题?如何高效的拷贝内存 中的数据
- how to use movntdqa to avoid cache pollution
- 计算机底层知识拾遗(一)理解虚拟内存机制
- How to access the control registers cr0,cr2,cr3 from a program
- 细说Cache-L1/L2/L3/TLB
- what-is-the-meaning-of-non-temporal-memory-accesses-in-x86
- How can the L1, L2, L3 CPU caches be turned off on modern x86/amd64 chips?
- UA list
- GDB
- 程序运行参数
- Linux下GDB的多线程调试
- CMake
- CMake快速入门教程:实战
- cmake打印变量值
- function
- source_group
- cmake_parse_arguments
- 编译.S文件
- add_definitions
- CMake添加-g编译选项
- Debug模式下启动
- Mysql
- Mysql联合查询union和union all的使用介绍
- MySQL数据库导入错误:ERROR 1064 (42000) 和 ERROR at line xx: Unknown command '\Z'.
- 解决MYSQL数据库 Table ‘xxx’ is marked as crashed and should be repaired 145错误
- C/C++
- c语言中static的作用
- strlen和sizeof有什么区别?
- printf
- Libuv中文文档之线程
- RapidJSON
- gcc/g++ 实战之编译的四个过程
- __thread
- TARGET_LINK_LIBRARIES
- MAP_HUGETLB
- 使用Intel格式的汇编
- __m128i
- emmintrin.h
- _mm_stream_si128
- _mm_stream_load_si128
- _mm_load_si128
- _mm_xor_si128
- _mm_store_si128
- _mm_cvtsi128_si64
- Intel SSE指令集
- _mm_set_epi64x
- _mm_aesenc_si128
- _umul128
- _mm_malloc
- reinterpret_cast
- strlen
- 读取UTF-8的txt文件发现开头的多三个字节的问题
- PHP
- php计算函数执行时间的方法
- 框架
- Json Rpc远程调用框架
- PHP多进程
- PHP CLI模式下的多进程应用
- php多进程总结
- 优化
- PHP7 优化
- 让你的PHP7更快(GCC PGO)
- PHP的性能演进(从PHP5.0到PHP7.1的性能全评测)
- PHP字符串全排列算法
- 获取服务器基本信息
- cookie
- phpstudy2018 安装xdebug扩展
- 软件下载
- PHP mysqli_error() 函数
- PHP Session 变量
- curl
- curl_getinfo
- 获取请求头
- PHP使用CURL获取302跳转后的地址实例
- PHP基于cURL实现自动模拟登录
- PHP获取远程图片大小(CURL实现)
- CURL模拟登录
- curl模拟登录提交(从目录中获取文件)
- CURL HTTPS
- curl帮v
- rename
- copy
- JSON
- json_encode
- json_decode
- json_last_error_msg
- json_last_error
- PHP json_encode中文乱码解决方法
- var_dump
- PHPStorm与Xdebug设置
- Xdebug原理以notepad为例
- str_pad
- pack
- PHP二进制与字符串之间的相互转换
- PHP执行系统命令(简介及方法)
- 函数
- 十进制转二进制
- 字符串到ASSCI
- 字符串转二进制
- 合并两个表
- 图像识别
- Tesseract
- 虚拟机
- vmware下Kali 2.0安装VMware Tools
- 安装 VMware tools出现“正在进行简易安装时,无法手动启动VMware tools安装”
- 爬虫
- 有哪些好的数据来源或者大数据平台?
- Cygwin
- Git 常用命令
- 排列组合
- 含重复元素序列的全排列
- 全排列的非递归和递归实现(含重复元素)
- GitBook
- 编辑环境
- visual studio code
- 2名数学家或发现史上最快超大乘法运算法,欲破解困扰人类近半个世纪的问题
- 系统预定义常量
- 指令集
- SSE
- _MSC_VER
- msys2
- 安装cmake
- MSYS2 更新源
- 讲Cmake msys32使用问题解答 CXX CMAKE_C_COMPILER配置详解
- VirtualBox
- 解决virtualbox只能安装32位系统的问题
- Ubuntu
- 使用AES-NI的编译参数
- debian下安装内核源码的方法
- tar.xz结尾的文件的解压方法
- Linux命令
- insmod
- fatal error: openssl/bio.h
- 准备module的编译环境(kali)
- Ubuntu/Debian 之内核模块开发准备
- dmesg的详细用法
- Linux系统开机自动加载驱动module
- linux /Module 浅析(转载)
- Kali
- 找回gpedit
- Enable the Lock Pages in Memory Option (Windows)
- TLA
- 双系统
- 显卡
- 显示no CUDA的解决过程
