標籤:pcl XML 查看 href stack class bytecode cto bcmath
本文是最初是來自國外的這篇: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 Team Dev近 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 );
- /***
- original benchmark script code here
- ***/
- 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 效能感興趣的開發人員分享這篇文章。
PHP的效能演化(從PHP5.0到PHP7.1的效能全評測)