當前位置:才華齋>設計>網頁設計>

百度工程師講PHP函式的實現原理及效能分析

網頁設計 閱讀(7.45K)

類方法

百度工程師講PHP函式的實現原理及效能分析

類方法其執行原理和使用者函式是相同的,也是翻譯成opcodes順次呼叫。類的實現,zend用一個數據結構zend_class_entry來實現,裡面儲存了類相關的一些基本資訊。這個entry是在php編譯的時候就已經處理完成。

在 zend_function的common中,有一個成員叫做scope,其指向的就是當前方法對應類的zend_class_entry。關於php中面向物件的實現,這裡就不在做更詳細的介紹,今後將專門寫一篇文章來詳述php中面向物件的實現原理。就函式這一塊來說,method實現原理和 function完全相同,理論上其效能也差不多,後面我們將做詳細的效能對比。

效能對比

函式名長度對效能的影響

》》測試方法 對名字長度為1、2、4、8、16的函式進行比較,測試比較它們每秒可執行次數,確定函式名長度對效能的影 響

》》測試結果如下圖

》》結果分析

從圖上可以看出,函式名的長度對效能還是會有一定的影響。一個長度為1的函式和長度為16的 空函式呼叫 ,其效能差了1倍。分析一下原始碼不難找到原因,如前面敘述所說,函式呼叫的時候zend會先在一個全域性的funtion_table中通過函式名查詢相關資訊,function_table是一個雜湊表。必然的,名字越長查詢所需要的時間就越多。 因此,在實際編寫程式的時候,對多次呼叫的函式,名字建議不要太長。

雖然函式名長度對效能有一定影響,但具體有多大呢?這個問題應該還是需要結合實際情況來考慮,如果一個函式本身比較複雜的話,那麼對整體的效能影響並不大。一個建議是對於那些會呼叫很多次,本身功能又比較簡單的函式,可以適當取一些言簡意賅的名字。

函式個數對效能的影響

》》測試方法

在以下三種環境下進行函式呼叫測試,分析結果:1.程式僅包含1個函式 2.程式包含100個函式 3.程式包含1000個函式。測試這三種情況下每秒所能呼叫的函式次數

》》測試結果如下圖

結果分析

從測試結果可以看出,這三種情況下效能幾乎相同,函式個數增加時效能下降微乎其微,可以忽略。從實現原理分析,幾種實現下唯一的區別在於函式獲取的部分。如前文所述,所有的函式都放在一個hash表中,在不同個數下查詢效率都應該還是接近於O(1),所以效能差距不大。

不同型別函式呼叫消耗

》》測試方法

選取使用者函式、類方法、靜態方法、內建函式各一種,函式本身不做任何事情,直接返回,主要測試空函式呼叫的消耗。測試結果為每秒可執行次數 測試中為去除其他影響,所有函式名字長度相同

》》測試結果如下圖

》》結果分析

通過測試結果可以看到,對於使用者自己編寫的php函式,不管是哪種型別,其效率是差不多的,均在280w/s左右。如我們預期,即使是空調,內建函式其效率也要高很多,達到780w/s,是前者是3倍。可見,內建函式呼叫的開銷還是遠低於使用者函式。從前面原理分析可知主要差距在於使用者函式呼叫時初始化符號表、接收引數等操作。

內建函式和使用者函式效能對比

》》測試方法

內建函式和使用者函式的效能對比,這裡我們選取幾個常用的函式,然後用php實現相同功能的函式進行一下效能對比。測試中,我們選取字串、數學、陣列中各一個典型進行對比,這幾個函式分別是字串擷取(substr)、10進位制轉2進位制(decbin)、求最小值(min)和返回陣列中的所以 key(array_keys)。

》》測試結果如下圖

》》結果分析

從測試結果可以看出,如我們預期,內建函式在總體效能上遠高於普通使用者函式。尤其對於涉及到字串類操作的函式,差距達到了1個數量級。因此,函式使用的一個原則就是如果某功能有相應的內建函式,儘量使用它而不是自己編寫php函式。對於一些涉及到大量字串操作的功能,為提高效能,可以考慮用擴充套件來實現。比如常見的富文字過濾等。

和C函式效能對比

》》測試方法

我們選取字串操作和算術運算各3種函式進行比對,php用擴充套件實現。三種函式是簡單的一次演算法運算、字串比較和多次的演算法運算。除了本身的兩類函式外,還會測試將函式空調開銷去掉後的效能,一方面比對一下兩種函式(c和php內建)本身的效能差異,另外就是側面印證空調函式的.消耗 測試點為執行10w次操作的時間消耗

》》測試結果如下圖

》》結果分析

內建函式和C函式的開銷在去掉php函式空呼叫的影響後差距較小,隨著函式功能越來越複雜,雙方效能趨近於相同。這個從之前的函式實現分析中也容易得到論證,畢竟內建函式就是C實現的。函式功能越複雜,c和php的效能差距越小 相對c來說,php函式呼叫的開銷大很多,對於簡單函式來說效能還是有一定影響。因此php中函式不宜巢狀封裝太深。

偽函式及其效能

在php中,有這樣一些函式,它們在使用上是標準的函式用法,但底層實現卻和真正函式呼叫完全不同,這些函式不屬於前文提到的三種function中的任何一類,其實質是一條單獨的opcode,這裡估且叫做偽函式或者指令函式。

如上所說,偽函式使用起來和標準的函式並無二致,看起來具有相同的特徵。但是他們最終執行的時候是被zend反映成了一條對應的指令(opcode)來呼叫,因此其實現更接近於if、 for、算術運算等操作。

》》php中的偽函式

isset

empty

unset

eval

通過上面的介紹可以看出,偽函式由於被直接翻譯成指令來執行,和普通函式相比少了一次函式呼叫所帶來的開銷,因此效能會更好一些。我們通過如下測試來做一個對比。 Array_key_exists和isset兩者都可以判斷陣列中某個key是否存在,看一下他們的效能

從圖上可以看出,和 array_key_exists相比,isset效能要高出很多,基本是前者的4倍左右,而即使是和空函式呼叫相比,其效能也要高出1倍左右。由此也側面印證再次說明了php函式呼叫的開銷還是比較大的。