Swoole 的疑惑
某次部落格的文章中,有訪客留言詢問一個問題:
「都有 Swoole,OPcache 還需要嗎?」
這個問題我並不是非常理解,但我認知上 Swoole 與 OPcache 是兩個不同的東西。 但是我也不是很確定,所以我上 Facebook 的 PHP 社群詢問,得到很多高手回答。
這個筆記整理各位高手的回答,也希望自己可以以此當作學習的起始點,去找尋回答中自己不知道的知識點並延伸學習
回答重點整理
OPcache 扮演的角色是在 interpret 過程中將 compile 成 opcode 的結果 cache 起來達到加速的目的。
Swoole、RoadRunner 或是 ReactPHP 這種 Server 運行模式是將程式常駐執行,避免每次請求需要重新載入重複的檔案與程式初始化來加速。
這兩種優化的方向是不同的,也互不衝突,至於 OPcache 有沒有效果是另外的事了,原則上開啟 OPcache 是能加速的,但會視你的機器、程式與 OPcache 設定而有不同的結果。
延伸思考題:那 JIT 對於 Swoole 模式下執行的程式是有幫助的嗎?
如果在 swoole, roadrunner, reactphp, amphhp 的架構下,且在服務沒有被重啟的狀況下 OPcache 應該只有第一次初始化會有幫助。
延伸思考題:所以 swoole 的架構下需要打開 JIT 嗎?
在 worker 沒有重啟的前提下 OPcache 的確只會發生在初始化的請求 (或是運行中有動態載入其他未初始化的 PHP 檔案時),而 interpret 過的 opcode 就會一起被常駐在記憶體中,但通常為了防止 memory leak,都會將 worker 設計為執行 N 次請求後重新啟動,因此 OPcache 基本上還是會持續有作用。
而 JIT 則是基於 opcode 在背後進行 hot code detect 和 JIT compile,將部分 opcode 編譯為 machine code 來加速 CPU bound 的程式,但由於 JIT 流程本身需要一定程度的 CPU 開銷,所以使用錯誤的情況下有可能讓效率變得比原本更差,但通常對於 CPU 密集型的程式有顯著的加速效果。
所以在 Swoole 中開不開 JIT 也是看情境而決定,會特別這樣問是曾經聽過有人會誤解成:Swoole 本身是 C++ extension,所以 JIT 本身沒有額外作用。這是錯誤的迷思,因為只有 Swoole 提供的相關功能才是用 C++ 寫的,業務邏輯本身還是 PHP Code,而業務邏輯的 PHP Code 使用了 JIT 後會不會加速就端看情境了 (因為大部分的 web 情境下其實 IO 的比重來的高很多)。
OPcache 是省掉 parse script 這一段
JIT 是省掉 zend vm 這一段。
在比較長的生命週期的系統裡,程式負載高的部份應該都會一直存活著。OPcache 和 JIT 大部份都幫不上忙,所以 OPcache 或 JIT 開不開在效能上不會有太顯著的差異
但 JIT 就你所說的 CPU bound 會有顯著的效能差異。但要真的讓它有顯著差異會有幾個條件
- PHP code 必須用強型別的方式來撰寫
- 拿 PHP 來寫 CPU bound 的程式
第一個條件沒達到 JIT 也快不起來
worker 重啟次數越少 OPcache 的幫助的確是越有限,但 JIT 對於 CPU 密集場景下的幫助還是比較顯著的。
在有型別宣告的前提下能讓 JIT 在型別推斷上更有效率,但也不代表沒有型別宣告下 JIT 會完全沒作用,JIT 還是會在執行過程中推斷變數的形態來完成優化 (當然相較強型別的情況下效率沒那麼好),以下面連結中的範例就是沒有加上任何型別宣告,但是 JIT 的效果還是很顯著的,可參考這篇文章。