本文是最初是來自國外的這篇:PHP Performance Evolution 2016, 感謝高可用架構公衆號翻譯成了中文版, 此處是轉載的高可用架構翻譯後的文章從PHP 5到PHP 7性能全評測(含未發佈的JIT版PHP 8對比), 稍微調整了格式而成。
php
導讀:PHP 是 Web 開發最經常使用的語言,每一個大版本的更新都帶來很多新特性和性能提高。特別是 PHP 7.0 的發佈,帶來 PHP 性能飛躍。本文做者對各個 PHP 版本進行了 CPU 性能基準測試,而且帶來了PHP下個大版本的消息。本文中文版由高可用架構志願者翻譯。html
自 1994 年 Rasmus Lerdorf 建立 PHP 以來, PHP 語言經歷了許多改進,其中性能是開發人員在評估新版本時考慮的主要標準之一。mysql
閱讀這篇文章,能夠了解從 PHP 5 到 7(包括 7.1)的性能提高,同時也將瞭解到即將加入到 PHP 8 的試驗性的 JIT 分支版本的性能。git
簡介
本文將根據時間做出更新,增長更多信息和基準測試結果,包括還沒有發佈的新版本,以便更好地瞭解多年來 PHP 性能演變。若是您有更正或建議改進,請在文後留言。github
自 1994 年 Rasmus Lerdorf 建立 PHP 以來, PHP 語言經歷了激烈的演進。雖然初版是一個簡單的一人開發的 CGI 程序,Rasmus Lerdorf、Andi Gutmans 和 Zeev Suraski 加入了該語言的第三個版本的開發,並根本性從新設計。從那以後, PHP 開發組也建立並發展起來。sql
隨着項目的發展,因爲 PHP 3 自然的可擴展性, PHP 在覈心和附加擴展開發的功能獲得了蓬勃發展,如網絡通訊,解析,緩存和數據庫支持。shell
語言自己也在發展,帶來了一系列的改進。這包括支持面向對象的結構,例如類,接口, 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.5
- 5.1.6
- 5.2.17
- 5.3.29
- 5.4.45
- 5.5.38
- 5.6.28
- 7.0.13
- 7.1.0
- PHP-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基準測試的結果以下所示:
CPU基準測試
(1)測試不能在 5.3 以前的版本上運行,由於它使用了還沒有實現的對象功能。
(2)此列中的結果有點偏頗,由於基準須要至少 PHP 5.3 運行。把它們當成純粹說明,由於他們不能與 PHP 5.0 性能進行比較。
(3)這是一個 mandelbrot.php 腳本的修改版本,它運行得太快,在 7.1.0 和試驗 JIT 分支沒法準確的統計時間,咱們在腳本中運行計算 100 次而不是 1 次。
固然,這些都是純 CPU 的基準測試。它們不涵蓋 PHP 性能的全部方面,它們可能不表明真實狀況。可是結果足夠顯著,足以說明幾個方面的問題:
- PHP 5.1 將 PHP 5.0的 性能提升了一倍多
- 5.2 和 5.3 帶來了他們本身的一些性能加強,但他們沒有像5.1版本那樣引人注目。
- 5.4 版本是一個大的性能改進。(這裏有我曾經分享過的PHP5.4的性能優化的演講PPTPHP-5.4 Performance)
- opcache 擴展插件與 5.5 和 5.6 版捆綁在一塊兒。當相同的腳本在 Web 服務器連續運行時,因爲更快的代碼加載會帶來性能加強。可是,opcache 不會真正顯示其在CLI模式下執行腳本的優點。
- PHP 7.0 是性能方面的一個重大突破。 Zend Engine 已經徹底從新設計,咱們能夠在這裏看到這項工做的結果。(這裏有我曾經分享過的PHP7的性能優化的演講的PPT The secret of PHP7′s Performance )
- PHP 7.1 在 opcache 擴展中引入了 opcode 優化。這再次解釋了上述表格中當與 7.0 相比時,性能的增益。(這裏有我曾經分享過的PHP7.1的性能優化的演講PPTPHP 7.1′s New Features and 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 分支版
性能如何衡量
基準化比單純運行 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 );
-
- fprintf( STDERR, microtime( true ) - $__start__);
- ?>
執行 2 次運行,以確保 PHP 可執行文件和基準測試腳本內容都在操做系統緩存中
運行腳本 5 次,並提取最小,最大和平均運行時間,如腳本報告。 本文僅顯示平均運行時間,稱之爲「腳本運行時間」。
php.ini 文件以下所示:
- engine = On
- short_open_tag = Off
- realpath_cache_size = 2M
- max_execution_time = 86400
- memory_limit = 1024M
- error_reporting = 0
- display_errors = 0
- display_startup_errors = 0
- log_errors = 0
- default_charset = "UTF-8"
-
- [opcache]
- zend_extension=opcache.so
- opcache.enable=1
- opcache.enable_cli=1
- opcache.optimization_level=-1
- opcache.fast_shutdown=1
- opcache.validate_timestamps=1
- opcache.revalidate_freq=60
- opcache.use_cwd=1
- opcache.max_accelerated_files=100000
- opcache.max_wasted_percentage=5
- opcache.memory_consumption=128
- opcache.consistency_checks=0
- opcache.huge_code_pages=1
-
- // PHP 8/Next only
- opcache.jit=35
- opcache.jit_buffer_size=32M
分析運行結果
使用 Unix time 命令來計時,輸出以下所示:
- $ time php bench.php
- real: 0m1.96s
- user: 0m1.912s
- sys: 0m0.044s
第一個值,real : 是命令開始到終止之間的時間(當你回到 shell 提示符)。
第二個值,user :說明在用戶模式中花費的時間(在咱們的例子中,這是在 php 可執行文件中花費的時間)。
最後一個值 sys :說明在操做系統(內核)調用中花費的時間。這個值應該是最小的,可是若是你的代碼訪問緩慢的設備結果會比較大。重負載的操做系統也可能影響此處報告的值。
在空閒系統上一般,數量(user + sys)應該很是接近 real。這是在上面的例子中的狀況:user + sys = 1.956s,real 是 1.960s。 0.004s 的差別不屬於當前進程:它僅僅意味着操做系統執行任務所花費的額外時間,例如調度。
同一個腳本在一個負載很重的系統上執行,並行編譯 3 個不一樣的 PHP 版本:
- $ time php bench.php
- real: 0m7.812s
- user: 0m2.02s
- sys: 0m0.101s
在這裏我清楚地看到,系統自己的重負載對使用的時間(也許在系統時間)有重大影響。
這就是爲何我在這個基準中保留一個額外的值,操做系統開銷,這是調用的時間和(用戶+系統)時間之間的差。
在純 CPU 基準測試活動期間,我確保在 99% 以上的時間,這個值嚴格小於 100 毫秒,即便運行須要幾十秒鐘完成的腳本。
結論
本文的目的是給你一個不一樣版本PHP性能的概述,從 5.0 開始,到當前正在開發的最新版本,使用一組已知的基準腳本。
它還爲您提供了由每一個連續 PHP 版本解決的性能改進方面的列表。
本文將隨着新的 PHP 版本的公佈而更新,而且未來會添加新的基準測試結果。 我也但願添加一些真實世界的 PHP 應用程序,如 WordPress 的基準測試結果。
若是您有任何問題或發現不許確,請隨時發表評論。 同時,與其餘對 PHP 性能感興趣的開發人員分享這篇文章。