1. 程式人生 > 實用技巧 >從PHP 5到PHP 7效能全評測(含未釋出的JIT版PHP 8對比)

從PHP 5到PHP 7效能全評測(含未釋出的JIT版PHP 8對比)

本文是最初是來自國外的這篇: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操作的任務例如訪問檔案,網路或資料庫連線)。 使用的基準測試指令碼如下所示:

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基準測試的結果如下所示:

(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的效能優化的演講的PPTThe 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編譯。

編譯原始碼

在構建完整發行版之前,使用以下選項執行配置指令碼:

--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 毫秒,即使執行需要幾十秒鐘完成的指令碼。

特別鳴謝

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

本文地址:

轉載:www.laruence.com/2020/06/12/5902.h...

以上內容希望幫助到大家,對PHP後端技術,對PHP架構技術感興趣的朋友,我的官方群點選此處,一起學習,相互討論。

群內已經有管理將知識體系整理好(原始碼,學習視訊等資料),歡迎加群免費領取。

學習資料、文件、面試題、視訊 點選連結免費獲取​shimo.im