【編者按】此前,閱讀過了很多關於 PHP 效能分析的文章,不過寫的都是一條一條的規則,而且,這些規則並沒有上下文,也沒有明確的實驗來體現出這些規則的優勢,同時討論的也側重於一些文法要點。本文就改變 PHP 效能分析的角度,並通過執行個體來分析出 PHP 的效能方面需要注意和改進的點。
對 PHP 效能的分析,我們從兩個層面著手,把這篇文章也分成了兩個部分,一個是宏觀層面,所謂宏觀層面,就是 PHP 語言本身和環境層面,一個是應用程式層面,就是文法和使用規則的層面,不過不僅探討規則,更輔助以樣本的分析。
宏觀層面,也就是對 PHP 語言本身的效能分析又分為三個方面:
-
PHP 作為解釋性語言效能有其天然的缺陷
-
PHP 作為動態類型語言在效能上也有提升的空間
-
當下主流 PHP 版本本身語言引擎效能
一、PHP 作為解釋性語言的效能分析與提升
PHP 作為一門指令碼語言,也是解釋性語言,是其天然效能受限的原因,因為同編譯型語言在運行之前編譯成二進位代碼不同,解釋性語言在每一次運行都面對原始指令碼的輸入、解析、編譯,然後執行。如下是 PHP 作為解釋性語言的執行過程。
如上所示,從上圖可以看到,每一次運行,都需要經曆三個解析、編譯、運行三個過程。
那最佳化的點在哪裡呢?可以想見,只要代碼檔案確定,解析到編譯這一步都是確定的,因為檔案已不再變化,而執行,則由於輸入參數的不同而不同。在效能 最佳化的世界裡,至上絕招就是在獲得同樣結果的情況下,減少操作,這就是大名鼎鼎的緩衝。緩衝無處不在,緩衝也是效能最佳化的殺手鐧。於是乎 OpCode 緩衝這一招就出現了,只有第一次需要解析和編譯,而在後面的執行中,直接由指令碼到 Opcode,從而實現了效能提速。執行流程如下圖所示:
相對每一次解析、編譯,讀到指令碼之後,直接從緩衝讀取位元組碼的效率會有大幅度的提升,提升幅度到底有多大呢?
我們來做一個沒有 Opcode 緩衝的實驗。20 個並發,總共 10000 次請求沒有經過 opcode 緩衝的請求,,得到如下結果:
其次,我們在伺服器上開啟 Opcode 緩衝。要想實現 opcode 緩衝,只需要安裝 APC、Zend OPCache、eAccelerator 擴充即可,即使安裝了多個,也只啟用其中一個。注意的是,修改了 php.ini 配置之後,需要重新載入 php-fpm 的配置。
這裡分別啟用 APC 和 Zend OPCache 做實驗。啟用 APC 的版本。
可以看到,速度有了較大幅度的提升,原來每個請求 110ms,每秒處理請求 182 個,啟用了 APC 之後 68ms,每秒處理請求 294 個,提升速度將近 40%。
在啟用了 Zend Opcache 的版本中,得到同 APC 大致相當的結果。每秒處理請求 291 個,每請求耗時 68.5ms。
從上面的這個實驗可以看到,所用的測試頁面,有 40ms 以上的時間花在了文法解析和編譯這兩項上。通過將這兩個操作緩衝,可以將這個處理過程的速度大大提升。
這裡附加補充一下,OpCode 到底是什麼東東,OpCode 編譯之後的位元組碼,我們可以使用bytekit 這樣的工具,或者使用 vld PHP 擴充來實現對 PHP 的代碼編譯。如下是 vld 外掛程式解析代碼的運行結果。
可以看到每一行代碼被編譯成相應的 OpCode 的輸出。