PHP的性能演進(從PHP5.0到PHP7.1的性能全評測)

作爲一名php開發人員,你需要了解這些


本文是最初是來自國外的這篇:PHP Performance Evolution 2016, 感謝高可用架構公衆號翻譯成了中文版, 此處是轉載的高可用架構翻譯後的文章從PHP 5到PHP 7性能全評測(含未發佈的JIT版PHP 8對比), 稍微調整了格式而成。

導讀: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操作的任務例如訪問文件,網絡或數據庫連接)。

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

  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 毫秒,即使運行需要幾十秒鐘完成的腳本。

特別鳴謝

特別鳴謝 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 性能感興趣的開發人員分享這篇文章。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章