- 相關(guān)推薦
百度工程師講PHP函數的實(shí)現原理及性能分析
類(lèi)方法
類(lèi)方法其執行原理和用戶(hù)函數是相同的,也是翻譯成opcodes順次調用。類(lèi)的實(shí)現,zend用一個(gè)數據結構zend_class_entry來(lái)實(shí)現,里面保存了類(lèi)相關(guān)的一些基本信息。這個(gè)entry是在php編譯的時(shí)候就已經(jīng)處理完成。
在 zend_function的common中,有一個(gè)成員叫做scope,其指向的就是當前方法對應類(lèi)的zend_class_entry。關(guān)于php中面向對象的實(shí)現,這里就不在做更詳細的介紹,今后將專(zhuān)門(mén)寫(xiě)一篇文章來(lái)詳述php中面向對象的實(shí)現原理。就函數這一塊來(lái)說(shuō),method實(shí)現原理和 function完全相同,理論上其性能也差不多,后面我們將做詳細的性能對比。
性能對比
函數名長(cháng)度對性能的影響
》》測試方法 對名字長(cháng)度為1、2、4、8、16的函數進(jìn)行比較,測試比較它們每秒可執行次數,確定函數名長(cháng)度對性能的影 響
》》測試結果如下圖
》》結果分析
從圖上可以看出,函數名的長(cháng)度對性能還是會(huì )有一定的影響。一個(gè)長(cháng)度為1的函數和長(cháng)度為16的 空函數調用 ,其性能差了1倍。分析一下源碼不難找到原因,如前面敘述所說(shuō),函數調用的時(shí)候zend會(huì )先在一個(gè)全局的funtion_table中通過(guò)函數名查詢(xún)相關(guān)信息,function_table是一個(gè)哈希表。必然的,名字越長(cháng)查詢(xún)所需要的時(shí)間就越多。 因此,在實(shí)際編寫(xiě)程序的時(shí)候,對多次調用的函數,名字建議不要太長(cháng)。
雖然函數名長(cháng)度對性能有一定影響,但具體有多大呢?這個(gè)問(wèn)題應該還是需要結合實(shí)際情況來(lái)考慮,如果一個(gè)函數本身比較復雜的話(huà),那么對整體的性能影響并不大。一個(gè)建議是對于那些會(huì )調用很多次,本身功能又比較簡(jiǎn)單的函數,可以適當取一些言簡(jiǎn)意賅的名字。
函數個(gè)數對性能的影響
》》測試方法
在以下三種環(huán)境下進(jìn)行函數調用測試,分析結果:1.程序僅包含1個(gè)函數 2.程序包含100個(gè)函數 3.程序包含1000個(gè)函數。測試這三種情況下每秒所能調用的函數次數
》》測試結果如下圖
》》結果分析
從測試結果可以看出,這三種情況下性能幾乎相同,函數個(gè)數增加時(shí)性能下降微乎其微,可以忽略。從實(shí)現原理分析,幾種實(shí)現下唯一的區別在于函數獲取的部分。如前文所述,所有的函數都放在一個(gè)hash表中,在不同個(gè)數下查找效率都應該還是接近于O(1),所以性能差距不大。
不同類(lèi)型函數調用消耗
》》測試方法
選取用戶(hù)函數、類(lèi)方法、靜態(tài)方法、內置函數各一種,函數本身不做任何事情,直接返回,主要測試空函數調用的消耗。測試結果為每秒可執行次數 測試中為去除其他影響,所有函數名字長(cháng)度相同
》》測試結果如下圖
》》結果分析
通過(guò)測試結果可以看到,對于用戶(hù)自己編寫(xiě)的php函數,不管是哪種類(lèi)型,其效率是差不多的,均在280w/s左右。如我們預期,即使是空調,內置函數其效率也要高很多,達到780w/s,是前者是3倍?梢(jiàn),內置函數調用的開(kāi)銷(xiāo)還是遠低于用戶(hù)函數。從前面原理分析可知主要差距在于用戶(hù)函數調用時(shí)初始化符號表、接收參數等操作。
內置函數和用戶(hù)函數性能對比
》》測試方法
內置函數和用戶(hù)函數的性能對比,這里我們選取幾個(gè)常用的函數,然后用php實(shí)現相同功能的函數進(jìn)行一下性能對比。測試中,我們選取字符串、數學(xué)、數組中各一個(gè)典型進(jìn)行對比,這幾個(gè)函數分別是字符串截取(substr)、10進(jìn)制轉2進(jìn)制(decbin)、求最小值(min)和返回數組中的所以 key(array_keys)。
》》測試結果如下圖
》》結果分析
從測試結果可以看出,如我們預期,內置函數在總體性能上遠高于普通用戶(hù)函數。尤其對于涉及到字符串類(lèi)操作的函數,差距達到了1個(gè)數量級。因此,函數使用的一個(gè)原則就是如果某功能有相應的內置函數,盡量使用它而不是自己編寫(xiě)php函數。對于一些涉及到大量字符串操作的功能,為提高性能,可以考慮用擴展來(lái)實(shí)現。比如常見(jiàn)的富文本過(guò)濾等。
和C函數性能對比
》》測試方法
我們選取字符串操作和算術(shù)運算各3種函數進(jìn)行比對,php用擴展實(shí)現。三種函數是簡(jiǎn)單的一次算法運算、字符串比較和多次的算法運算。除了本身的兩類(lèi)函數外,還會(huì )測試將函數空調開(kāi)銷(xiāo)去掉后的性能,一方面比對一下兩種函數(c和php內置)本身的性能差異,另外就是側面印證空調函數的消耗 測試點(diǎn)為執行10w次操作的時(shí)間消耗
》》測試結果如下圖
》》結果分析
內置函數和C函數的開(kāi)銷(xiāo)在去掉php函數空調用的影響后差距較小,隨著(zhù)函數功能越來(lái)越復雜,雙方性能趨近于相同。這個(gè)從之前的函數實(shí)現分析中也容易得到論證,畢竟內置函數就是C實(shí)現的。函數功能越復雜,c和php的性能差距越小 相對c來(lái)說(shuō),php函數調用的開(kāi)銷(xiāo)大很多,對于簡(jiǎn)單函數來(lái)說(shuō)性能還是有一定影響。因此php中函數不宜嵌套封裝太深。
偽函數及其性能
在php中,有這樣一些函數,它們在使用上是標準的函數用法,但底層實(shí)現卻和真正函數調用完全不同,這些函數不屬于前文提到的三種function中的任何一類(lèi),其實(shí)質(zhì)是一條單獨的opcode,這里估且叫做偽函數或者指令函數。
如上所說(shuō),偽函數使用起來(lái)和標準的函數并無(wú)二致,看起來(lái)具有相同的特征。但是他們最終執行的時(shí)候是被zend反映成了一條對應的指令(opcode)來(lái)調用,因此其實(shí)現更接近于if、 for、算術(shù)運算等操作。
》》php中的偽函數
isset
empty
unset
eval
通過(guò)上面的介紹可以看出,偽函數由于被直接翻譯成指令來(lái)執行,和普通函數相比少了一次函數調用所帶來(lái)的開(kāi)銷(xiāo),因此性能會(huì )更好一些。我們通過(guò)如下測試來(lái)做一個(gè)對比。 Array_key_exists和isset兩者都可以判斷數組中某個(gè)key是否存在,看一下他們的性能
從圖上可以看出,和 array_key_exists相比,isset性能要高出很多,基本是前者的4倍左右,而即使是和空函數調用相比,其性能也要高出1倍左右。由此也側面印證再次說(shuō)明了php函數調用的開(kāi)銷(xiāo)還是比較大的。
【百度工程師講PHP函數的實(shí)現原理及性能分析】相關(guān)文章:
探討PHP函數的實(shí)現原理及性能07-07
PHP中的排序函數區別分析08-23
關(guān)于php堆排序實(shí)現原理與應用方法10-09
php中session的實(shí)現原理以及大網(wǎng)站應用應注意的問(wèn)題分析07-26
PHP的壓縮函數06-21
淺析php函數的實(shí)例06-08
php外部執行命令函數10-27
簡(jiǎn)單介紹php構造函數用法08-31
PHP中函數的使用說(shuō)明09-01