日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

php 8 jit,深入理解PHP8 JIT

發布時間:2024/9/30 php 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php 8 jit,深入理解PHP8 JIT 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

PHP 8的Just In Time是Opcache擴展的一部分,旨在在運行時將某些操作碼編譯為CPU指令。這意味著使用JIT時,Zend VM不需要解釋某些操作碼,而這些指令將直接作為CPU級指令執行。

PHP 8 JIT

PHP 8將帶來的最受好評的功能之一是Just In Time(JIT)編譯器。許多博客和社區都在談論它,并且肯定會引起很大的轟動,但是到目前為止,我發現關于JIT內部的細節很少。

經過多次研究和放棄后,我決定親自檢查PHP源代碼。結合我對C語言的一點了解以及到目前為止所收集的所有分散信息,我提出了這篇文章,希望它也能幫助您更好地了解PHP的JIT。

簡單來說: 當JIT按預期工作時,您的代碼將不會通過Zend VM執行,而是直接作為一組CPU級指令執行。

這就是JIT核心思想。

但是為了更好地理解它,我們需要考慮php在內部如何工作。不是很復雜,但是需要一些介紹。

PHP代碼如何執行?

我們都知道php是一種解釋語言。但這到底是什么意思?

每當您要執行PHP代碼(例如代碼段或整個Web應用程序)時,都必須經過php解釋器。

最常用的是PHP FPM和CLI解釋器。

他們的工作非常簡單:接收php代碼,對其進行解釋并向后吐出結果。

這通常發生在每種解釋語言上。有些語言可能會刪除一些步驟,但總體思路是相同的。

在PHP中,它是這樣的:

PHP代碼被讀取并轉換為一組關鍵字,即標記(Tokens)。這個過程允許解釋器理解在程序的哪一部分中寫了哪段代碼。這第一步叫做詞法分析或符號化。

有了Tokens后,PHP解釋器將分析這個Tokens集合,并嘗試理解它們。結果通過一個稱為解析的過程生成了一個抽象語法樹(AST)。這個AST是一組指示應該執行哪些操作的節點。例如,“echo 1 + 1”實際上應該表示“打印1 + 1的結果”,或者更實際一些“打印一個操作,操作是1 + 1”。

3 . 有了AST,理解操作和優先級就容易得多了。將這個樹轉換成可以執行的東西需要一個中間表示(IR),在PHP中我們稱之為操作碼。將AST轉換為操作碼的過程稱為編譯。

現在,有了操作碼,剩下就是執行代碼。PHP有一個名為Zend VM的引擎,它能夠接收操作碼列表并執行它們。在執行了所有操作碼之后,Zend VM就存在了,程序就終止了。

執行的過程使用下圖標識就更加清楚了。

非常直接,正如你們所能理解的。但這里有一個瓶頸:如果php代碼變化不是那么頻繁,那么每次執行代碼時對其進行詞法分析又有什么意義呢?

最后我們只關心操作碼,對吧? 沒錯! 這就是為什么存在Opcache擴展。

Opcache擴展

Opcache擴展是隨PHP附帶的,通常沒有什么理由禁用它。如果使用PHP,應該打開Opcache。

它的作用是為操作碼在內存中添加一個共享緩存層。它的工作是從AST中新生成的操作碼并緩存它們,以便進一步執行可以輕松跳過詞法分析和解析階段。

Opcache擴展的流程示意圖:

PHP使用Opcache的解釋流程。如果文件已經被解析,則php會為其獲取緩存的操作碼,而不是再次解析。

opcache完美地跳過了詞法分析,語法解析和編譯步驟。

注意:這就是PHP 7.4的預加載功能的亮點!它使您可以告訴PHP FPM解析代碼庫,將其轉換為操作碼并甚至在執行任何操作之前就對其進行緩存。

JIT即時編譯器有效地做什么?

如果Opcache可以更快地獲取操作碼,這樣它們就可以直接轉到Zend VM,那么JIT應該讓它們在跳過Zend VM的情況下運行。

Zend VM是一個用C編寫的程序,充當操作碼和CPU本身之間的一個層。JIT所做的是在運行時生成編譯后的代碼,這樣php就可以跳過Zend VM直接轉到CPU。理論上講,我們應該從中獲得性能提升。

起初,這對我來說很奇怪,因為為了編譯機器代碼,您需要為每種類型的體系結構編寫一個非常具體的實現。但事實上,它是相當合理的。

PHP的JIT實現使用名為DynASM (Dynamic Assembler)的庫,該庫將一組特定格式的CPU指令映射為許多不同CPU類型的匯編代碼。因此,Just In Time編譯器使用DynASM將操作碼轉換為特定于架構的機器碼。

不過,有一個想法困擾了我很長一段時間……

如果預加載能夠在執行前將php代碼解析為操作碼,而DynASM可以將操作碼編譯為機器碼(正好是及時編譯),那么為什么我們不使用提前編譯的方法直接編譯php呢?!

我從收聽Zeev的那集中得到的一個線索是PHP是弱類型的,這意味著PHP通常不知道變量的類型,直到Zend VM嘗試執行某個操作碼。

這可以通過查看zend_value聯合類型看出,它有許多指針指向一個變量的不同類型表示。無論何時Zend VM嘗試從zend_value中獲取值,它都會使用像ZSTR_VAL這樣的宏來嘗試從值聯合中訪問字符串指針。

例如,這個Zend VM處理程序應該處理一個“小于或等于”(<=)表達式。看看它是如何分支到許多不同的代碼路徑的,只是為了猜測操作數類型。

用機器碼復制這種類型推斷邏輯是不可行的,可能會使事情變得更慢。

在計算類型之后編譯所有內容也不是一個好選擇,因為編譯成機器碼是一項CPU密集型任務。所以在運行時編譯所有東西也是不好的。

JIT即時編譯器是如何工作的?

現在我們知道我們不能在編譯前推斷出足夠好的類型。我們還知道,在運行時進行編譯是昂貴的。JIT對PHP有什么好處?

為了平衡這個等式,PHP的JIT只嘗試編譯一些它認為可以得到回報的操作碼。為此,它對Zend VM正在執行的操作碼進行概要分析,并檢查哪些操作碼可以編譯。(根據您的配置)

當編譯某個操作碼時,它將把執行委托給編譯后的代碼,而不是委托給Zend VM。看起來如下:

PHP的JIT解釋流程。如果已編譯,則操作碼不會通過Zend VM執行。

所以在Opcache擴展中有一些指令檢測某個操作碼是否應該編譯。如果是,編譯器然后使用DynASM將該操作碼轉換為機器碼,并執行新生成的機器碼。

有趣的是,由于當前實現中編譯的代碼有兆字節限制(也是可配置的),因此代碼執行必須能夠在JIT和解釋代碼之間無縫切換。

我仍然不確定編譯部分什么時候有效地發生,但我想我現在真的不想知道。

因此性能的提高可能不會很大

為什么每個人都說大多數php應用程序不會從使用Just In Time編譯器中獲得很大的性能好處,我希望現在能夠清楚地知道這一點。以及為什么Zeev建議對應用程序進行分析并試驗不同的JIT配置是最好的方法。

如果您使用的是PHP FPM,編譯后的操作碼通常會在多個請求之間共享,但這仍然不能改變游戲規則。

這是因為JIT優化了cpu綁定操作,而現在大多數php應用程序都是I/O綁定的。如果你必須訪問磁盤或網絡,不管處理操作是否被編譯。計時也非常類似。

文章翻譯自https://thephp.website/en/issue/php-8-jit/

5.0

02

Post Views:

942

總結

以上是生活随笔為你收集整理的php 8 jit,深入理解PHP8 JIT的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。