編者按】此前,閱讀過了很多關於 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 的輸出。