PHP從PHP5.0到PHP7.1的性能全評測

本文是最初是來自國外的這篇: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操做的任務例如訪問文件,網絡或數據庫鏈接)。

使用的基準測試腳本以下所示:

  1. bench.php 可在PHP源代碼的 php-src/Zend 目錄
  2. micro_bench.php 也能夠在 PHP 源代碼發佈的 php-src/Zend 目錄中找到
  3. mandelbrot.php https://gist.githubusercontent.com/dstogov/12323ad13d3240aee8f1/raw/37fed3beb7e666b70e199bcf361af541b3c30d2d/b.php

基準腳本僅使用每一個PHP主要版本的最新小版本運行。所以,測試的版本以下:

  1. 5.0.5
  2. 5.1.6
  3. 5.2.17
  4. 5.3.29
  5. 5.4.45
  6. 5.5.38
  7. 5.6.28
  8. 7.0.13
  9. 7.1.0
  10. 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基準測試

CPU基準測試



(1)測試不能在 5.3 以前的版本上運行,由於它使用了還沒有實現的對象功能。
(2)此列中的結果有點偏頗,由於基準須要至少 PHP 5.3 運行。把它們當成純粹說明,由於他們不能與 PHP 5.0 性能進行比較。
(3)這是一個 mandelbrot.php 腳本的修改版本,它運行得太快,在 7.1.0 和試驗 JIT 分支沒法準確的統計時間,咱們在腳本中運行計算 100 次而不是 1 次。

 

純CPU測試曲線圖

固然,這些都是純 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 分支版

  • 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編譯。

編譯源代碼

在構建完整發行版以前,使用如下選項運行配置腳本:

  1. --prefix=/usr/local/php
  2. --disable-debug
  3. --disable-phpdbg
  4. --enable-mysqlnd
  5. --enable-bcmath
  6. --with-bz2=/usr
  7. --enable-calendar
  8. --with-curl
  9. --enable-exif
  10. --enable-fpm
  11. --with-freetype-dir
  12. --enable-ftp
  13. --with-gd
  14. --enable-gd-jis-conv
  15. --enable-gd-native-ttf
  16. --with-gettext=/usr
  17. --with-gmp
  18. --with-iconv
  19. --enable-intl
  20. --with-jpeg-dir
  21. --enable-mbstring
  22. --with-mcrypt
  23. --with-openssl
  24. --enable-pcntl
  25. --with-pdo-mysql=mysqlnd
  26. --with-png-dir
  27. --with-recode=/usr
  28. --enable-shmop
  29. --enable-soap
  30. --enable-sockets
  31. --enable-sysvmsg
  32. --enable-sysvsem
  33. --enable-sysvshm
  34. --enable-wddx
  35. --with-xmlrpc
  36. --with-xsl
  37. --with-zlib=/usr
  38. --enable-zip
  39. --with-mysqli=mysqlnd

注意,在編譯舊版時,上面的一些選項須要被禁用或被其餘替代,而且並非全部的擴展均可用或能夠被編譯。

運行基準測試

每一個基準測試都使用 PHP CLI 專用腳本運行,該腳本遵循如下步驟:

使用 microtime()函數從內部獲取腳本執行時間。 在此修改後,基準腳本將以下所示:

  1. <?php
  2.     $__start__ = microtime( true );
  3.     /***
  4. original benchmark script code here
  5. ***/
  6.     fprintf( STDERR, microtime( true ) - $__start__);
  7.  ?>

執行 2 次運行,以確保 PHP 可執行文件和基準測試腳本內容都在操做系統緩存中
運行腳本 5 次,並提取最小,最大和平均運行時間,如腳本報告。 本文僅顯示平均運行時間,稱之爲「腳本運行時間」。

php.ini 文件以下所示:

  1. engine = On
  2. short_open_tag = Off
  3. realpath_cache_size = 2M
  4. max_execution_time = 86400
  5. memory_limit = 1024M
  6. error_reporting = 0
  7. display_errors = 0
  8. display_startup_errors = 0
  9. log_errors = 0
  10. default_charset = "UTF-8"
  11.  
  12. [opcache]
  13. zend_extension=opcache.so
  14. opcache.enable=1
  15. opcache.enable_cli=1
  16. opcache.optimization_level=-1
  17. opcache.fast_shutdown=1
  18. opcache.validate_timestamps=1
  19. opcache.revalidate_freq=60
  20. opcache.use_cwd=1
  21. opcache.max_accelerated_files=100000
  22. opcache.max_wasted_percentage=5
  23. opcache.memory_consumption=128
  24. opcache.consistency_checks=0
  25. opcache.huge_code_pages=1
  26.  
  27. // PHP 8/Next only
  28. opcache.jit=35
  29. opcache.jit_buffer_size=32M

分析運行結果

使用 Unix time 命令來計時,輸出以下所示:

  1. $ time php bench.php
  2. real: 0m1.96s
  3. user: 0m1.912s
  4. sys: 0m0.044s

第一個值,real : 是命令開始到終止之間的時間(當你回到 shell 提示符)。

第二個值,user :說明在用戶模式中花費的時間(在咱們的例子中,這是在 php 可執行文件中花費的時間)。

最後一個值 sys :說明在操做系統(內核)調用中花費的時間。這個值應該是最小的,可是若是你的代碼訪問緩慢的設備結果會比較大。重負載的操做系統也可能影響此處報告的值。

在空閒系統上一般,數量(user + sys)應該很是接近 real。這是在上面的例子中的狀況:user + sys = 1.956s,real 是 1.960s。 0.004s 的差別不屬於當前進程:它僅僅意味着操做系統執行任務所花費的額外時間,例如調度。

同一個腳本在一個負載很重的系統上執行,並行編譯 3 個不一樣的 PHP 版本:

  1. $ time php bench.php
  2. real: 0m7.812s
  3. user: 0m2.02s
  4. sys: 0m0.101s

在這裏我清楚地看到,系統自己的重負載對使用的時間(也許在系統時間)有重大影響。

這就是爲何我在這個基準中保留一個額外的值,操做系統開銷,這是調用的時間和(用戶+系統)時間之間的差。

在純 CPU 基準測試活動期間,我確保在 99% 以上的時間,這個值嚴格小於 100 毫秒,即便運行須要幾十秒鐘完成的腳本。

結論

本文的目的是給你一個不一樣版本PHP性能的概述,從 5.0 開始,到當前正在開發的最新版本,使用一組已知的基準腳本。

它還爲您提供了由每一個連續 PHP 版本解決的性能改進方面的列表。

本文將隨着新的 PHP 版本的公佈而更新,而且未來會添加新的基準測試結果。 我也但願添加一些真實世界的 PHP 應用程序,如 WordPress 的基準測試結果。

若是您有任何問題或發現不許確,請隨時發表評論。 同時,與其餘對 PHP 性能感興趣的開發人員分享這篇文章。

相關文章
相關標籤/搜索