根據(jù)“TIOBE編程語言排行榜”(榜單雖然統(tǒng)計方式有局限,但是仍然不失為一個比較好的參考),2010年P(guān)HP最高曾經(jīng)在世界編程語言中排名第三。可見,PHP語言在PC互聯(lián)網(wǎng)時代的Web領(lǐng)域可謂叱咤風(fēng)云,擎天一柱。
在PHP程序員中,曾經(jīng)流傳著一個段子:
某女:你能讓這個論壇的人都吵起來,我就跟你吃飯。
PHP程序員:PHP是世界上最好的語言!
某論壇炸鍋了,各種吵架……
某女:服了你了,我們走吧!
PHP程序員:今天不行,我一定要說服他們,PHP必須是最好的語言。
好了,我們言歸正傳,語言本身無分好壞,只是在各自使用的場景中解決不同的問題。互聯(lián)網(wǎng)的時代車輪是很快的,隨著移動互聯(lián)網(wǎng)的到來,在短短四年多的時間里,移動端技術(shù)發(fā)展橫掃全球。與此同時,各種語言群雄并起,而昔日輝煌的PHP從原來的編程語言的榜單看,下降到第六位(2014年12月榜單)。于是,唱衰PHP的聲音此起彼伏。
但是,鳥哥(惠新宸,PHP語言開發(fā)者之一)在2014年的Qcon分享中有一個數(shù)據(jù),全球排名前100萬的網(wǎng)站中,81.3%使用的Web服務(wù)端腳本語言是PHP,2013年同期是78.3%。也就是說,PHP的在Web服務(wù)方面并沒有減少,只是在移動互聯(lián)網(wǎng)浪潮中,增加了很多的其他語言技術(shù)的應(yīng)用,進(jìn)而被稀釋了。
最近關(guān)于PHP7和HHVM的性能對比,成為了一個熱點的爭議話題,大家都在討論和關(guān)注哪一個才是PHP性能提升的未來。
HHVM(HipHop Virtual Machine)的起源HHVM是一個開源的PHP虛擬機,使用JIT的編譯方式以及其他技術(shù),讓PHP代碼的執(zhí)行性能大幅提升。據(jù)傳,可以將當(dāng)前版本的原生PHP代碼提升5-10倍的執(zhí)行性能。
HHVM起源于Facebook公司,F(xiàn)acebook早起的很多代碼是使用PHP來開發(fā)的,但是,隨著業(yè)務(wù)的快速發(fā)展,PHP執(zhí)行效率成為越來越明顯的問題。為了優(yōu)化執(zhí)行效率,F(xiàn)acebook在2008年就開始使用HipHop,這是一種PHP執(zhí)行引擎,最初是為了將Fackbook的大量PHP代碼轉(zhuǎn)成 C++,以提高性能和節(jié)約資源。使用HipHop的PHP代碼在性能上有數(shù)倍的提升。后來,F(xiàn)acebook將HipHop平臺開源,逐漸發(fā)展為現(xiàn)在的HHVM。
1. PHP為什么慢?
PHP的慢是相對于C/C++級別的語言來說,事實上,PHP語言最初的設(shè)計,就不是用來解決計算密集型的應(yīng)用場景。我們可以這樣粗略理解為,PHP為了提升開發(fā)效率,而犧牲了執(zhí)行效率。
我們知道PHP一個很大的特點,就是弱類型特性,也就是說,我可以隨意定義一個變量,然后給它隨意賦值為各種類型的數(shù)據(jù)。以一個int整型數(shù)字為例子,在C語言中:
int num = 200;//通常是4字節(jié)
但是,如果是PHP定義了一個同樣的變量,實際對應(yīng)的存儲結(jié)構(gòu)則是:
這個結(jié)構(gòu)體將會占據(jù)遠(yuǎn)比C變量多得多的內(nèi)存,PHP中定義方式如下:
$a = 200;//這變量將實際占用對比C變量很多倍的存儲空間。
其實對PHP來說,無論存儲什么類型的數(shù)據(jù),都是用上述“通殺”的結(jié)構(gòu)體實現(xiàn)。為了兼容PHP程序員的變量類型“亂入”,PHP做到了對開發(fā)者的友好,但是對執(zhí)行引擎很殘酷。單個變量內(nèi)存消耗可能還不明顯,一旦用到PHP的數(shù)組等,則復(fù)雜度指數(shù)上升(數(shù)組的實現(xiàn)是HashTable)。然后,Zend引擎執(zhí)行時,將這些PHP代碼編譯為opcode(PHP的中間字節(jié)碼,格式有點類似于匯編),由Zend引擎逐行解釋執(zhí)行。
無論是字符串的連接操作,還是數(shù)組的簡單修改等,幾乎都是“PHP程序員一句話,Zend引擎跑斷腿”的節(jié)奏。因此,同樣的操作,對比C來說,PHP消耗了更多的CPU和內(nèi)存等系統(tǒng)資源。除此之外,還有內(nèi)存自動回收、變量類型判斷等等,都會增加系統(tǒng)資源的消耗。
例如,我用純PHP實現(xiàn)的快速排序函數(shù)和原生sort函數(shù),排序10000個整型數(shù)字,來做一個耗時對比,結(jié)果如下:
原生的sort耗時3.44 ms,而我們自己實現(xiàn)的html' target='_blank'>PHP函數(shù)sort則是68.79 ms。我們發(fā)現(xiàn),兩者執(zhí)行效率差距巨大。我的測試方式,是計算函數(shù)執(zhí)行前后的時間間隔,而不是整個PHP腳本從啟動到結(jié)束的時間。PHP腳本啟動和關(guān)閉過程,本身有著一系列的初始化和清理工作,也會占據(jù)不少的耗時。
通常情況下,PHP執(zhí)行效率的排行是:
最快的是PHP語言結(jié)構(gòu)(isset、echo等),PHP語言的一部分(它們根本不是函數(shù))。
然后比較快的就是PHP的原生和拓展函數(shù)。PHP拓展,基于Zend API之上,用C實現(xiàn)的功能,執(zhí)行效率和C++/Java是屬于同一個數(shù)量級的。
真正慢的就是,我們通過PHP自己寫的代碼和函數(shù)。例如,假如我們使用的比較重的純PHP實現(xiàn)的框架,因為框架本身的模塊很多,所以,會明顯拖累語言層面的執(zhí)行效率,同時占據(jù)更多的內(nèi)存。(國內(nèi)的Yaf框架,以拓展的方式實現(xiàn),因此執(zhí)行效率遠(yuǎn)快于純PHP寫的框架)
在一般情況下,我們并不推薦用過PHP實現(xiàn)邏輯復(fù)雜計算類型的功能,尤其是Web系統(tǒng)流量比較大的場景下。因此,PHP程序員應(yīng)該對PHP的各種原生函數(shù)和各類拓展有一個比較廣泛的了解,在具體的功能實現(xiàn)場景中,尋求更原生的解決方案(原生接口或者拓展),而不是自己寫一堆復(fù)雜的PHP代碼來實現(xiàn)這類型功能。
如果有足夠的PHP拓展開發(fā)實力,將這類型業(yè)務(wù)功能重寫為一個PHP拓展,也會大幅提升代碼的執(zhí)行效率。這是一個非常不錯的方式,也被廣泛應(yīng)用PHP優(yōu)化中。但是,自己編寫的PHP業(yè)務(wù)拓展的缺點也很明顯:
拓展開發(fā)耗時比較長,需求變更的時候修改也復(fù)雜,寫得不好可能會影響Web服務(wù)穩(wěn)定性。(例如,在Apache的worker模式下,多線程場景下掛掉,會影響同一個進(jìn)程下的其他正常子線程。如果是多線程的Web模式,編寫拓展還需要支持線程安全)
拓展在PHP版本升級的時候,可能需要做額外的兼容工作。
人員變動后的維護(hù)和接手成本也比較高。
實際上,在互聯(lián)網(wǎng)一線企業(yè)中,更常見的解決方案,并非增加PHP拓展,而用C/C++獨立寫一個服務(wù)server,然后PHP通過socket和服務(wù)server通信來完成業(yè)務(wù)處理,并不將PHP本身和業(yè)務(wù)耦合在一起。
不過,Web服務(wù)大部分的性能瓶頸都在網(wǎng)絡(luò)傳輸和其他服務(wù)server的耗時上(例如MySQL等),PHP執(zhí)行的耗時在整體耗時的占用比例非常小,所以從業(yè)務(wù)角度來說,影響可能并不明顯。
2. HHVM提升PHP執(zhí)行性能的方式
HHVM提升PHP性能的途徑,采用的方式就是替代Zend引擎來生成和執(zhí)行PHP的中間字節(jié)碼(HHVM生成自己格式的中間字節(jié)碼),執(zhí)行時通過JIT(Just In Time,即時編譯是種軟件優(yōu)化技術(shù),指在運行時才會去編譯字節(jié)碼為機器碼)轉(zhuǎn)為機器碼執(zhí)行。Zend引擎默認(rèn)做法,是先編譯為opcode,然后再逐條執(zhí)行,通常每條指令對應(yīng)的是C語言級別的函數(shù)。如果我們產(chǎn)生大量重復(fù)的opcode(純PHP寫的代碼和函數(shù)),對應(yīng)的則是Zend多次逐條執(zhí)行這些C代碼。而JIT所做的則是更進(jìn)一步,將大量重復(fù)執(zhí)行的字節(jié)碼在運行的時候編譯為機器碼,達(dá)到提高執(zhí)行效率的目的。通常,觸發(fā)JIT的條件是代碼或者函數(shù)被多次重復(fù)調(diào)用。
普通的PHP代碼,因為無法固定變量的類型,需要額外添加判斷類型的邏輯代碼,這樣PHP代碼是不利于CPU執(zhí)行和優(yōu)化的。因此,HHVM通常需要用到Hack寫法(為了兼容某種特性而額外添加的技巧性質(zhì)的代碼)的PHP代碼來“配合”,就是為了讓變量類型固定,方便虛擬機編譯執(zhí)行。PHP追求以一種形式來容納一切類型,而Hack則可以將被容納的一切標(biāo)記上確定的類型。
PHP代碼的Hack寫法的例子:
上面的例子中,PHP代碼主要被添加上了變量類型。Hack寫法的總體方向,就是將之前“動態(tài)”的寫法變?yōu)椤办o態(tài)”的寫法,來配合HHVM。
HHVM因為它的高性能而吸引了不少人的關(guān)注,一些一線互聯(lián)網(wǎng)公司也開始跟進(jìn)使用。從純語言執(zhí)行性能測試結(jié)果來看,HHVM領(lǐng)先了開發(fā)中的PHP7版本不少。
不過,從具體業(yè)務(wù)場景來看,HHVM和PHP7的差距并沒有那么大,以WordPress開源博客首頁為測試場景的結(jié)果中,他們目前的差距并不明顯。
但是,PHP7目前還在開發(fā)中,就已經(jīng)可用的技術(shù)方案來看,目前的HHVM略勝一籌。不過,HHVM的部署和應(yīng)用都存在一些的問題:
服務(wù)部署比較復(fù)雜,有一定維護(hù)成本。
對PHP原生代碼并非完整支持,PHP拓展也需要做適當(dāng)?shù)募嫒荨?/p>
HHVM是個新虛擬機,長時間運行有內(nèi)存泄露。(據(jù)說,一線互聯(lián)網(wǎng)公司在應(yīng)用這個技術(shù)時,是通過自己打Patch的方式解決內(nèi)存泄露)
HHVM畢竟是一個相對比較新的開源項目,發(fā)展到成熟仍然需要一定時間。
PHP7的性能革新PHP長期以來飽受批評的性能問題,將會在這個版本得到大幅度的改善。版本中間沒有PHP6哈,據(jù)說,是因為這個版本曾經(jīng)立過項目,后來大部分功能都在5.x的版本里實現(xiàn)了,為了避免混淆,下一個大版本直接就是PHP7。(幾年以前,我還看到過關(guān)于PHP6的書籍。)
1. PHP7的介紹
雖然PHP7的正式版本可能要到2015年的10月份才發(fā)布,不過明年6月份應(yīng)可以看見一個測試版本了,之后是3-4個月的質(zhì)量保證。
PHP社區(qū)的項目計劃如下:
因為項目仍然處于開發(fā)中的原因,從表格中,可以看見的特性描述都比較模糊。肯定有更多的其他特性,只是尚未公布。下面的這些,是從PHP社區(qū)看見的,因為PHP7是一個開發(fā)中的項目,下面的這些也不一定準(zhǔn)確,不過,不妨礙我們一起來看看。
PHPNG(PHP next generation,下一代PHP),對Zend執(zhí)行引擎本身的各種性能優(yōu)化,其中JIT,可能會實現(xiàn)在Zend Opcache組件中。
AST(Abstract Syntax Tree,抽象語法樹),目的是在PHP編譯過程引入一個中間件,替代直接從解釋器吐出opcode的方式。讓解釋器和編譯器解耦,可以減少大量Hack代碼,同時,讓實現(xiàn)更容易理解和維護(hù)。
uniform variable syntax(統(tǒng)一變量語法),引入一種內(nèi)部一致和完整的變量語法,讓PHP的解析器更完整地支持各種類型的變量。部分變量的用法需要調(diào)整,例如變量的變量$$a等。
支持integer semantics(整型語義),例如NaN、Infinity、<<、>>,修正list()的一致性等等。
上面的特性中,最令人期待的就是PHPng的性能優(yōu)化,PHP社區(qū)已經(jīng)放出了一些性能的測速數(shù)據(jù)。從數(shù)據(jù)上看,PHPng的執(zhí)行性能比起項目啟動之初,已經(jīng)有接近1倍的提升。這個成績已經(jīng)非常不錯,況且,最關(guān)鍵的是PHP7的優(yōu)化計劃還有很多尚未完成。等到都全部完成了,相信我們可以看見一個性能更高的PHP7。
這測速數(shù)據(jù)是來自于PHP社區(qū)(wiki.php.net/phpng),截取了一部分的數(shù)據(jù):
對其當(dāng)前PHP5.6版本,PHPNG的10月份性能提升已經(jīng)非常明顯了:
簡單翻譯下:
綜合測試速度提升35%。
在實際應(yīng)用場景有20%-70%的速度提升(WordPress首頁有60%的提升)
更少的內(nèi)存消耗
支持大部分常用的SAPIs
支持大部分的PHP拓展綁定到資源分配(69個完成,6個待遷移)
提供堪比HHVM3.3.0的執(zhí)行速度
2. PHP的弱類型爭議
PHP被爭議的特點很多,但是隨著語言版本的發(fā)布和完善,功能和特性方面的批評開始變少了。但是,PHP的“弱類型”特性,卻明顯受到更多的爭議,從HHVM通過Hack的方式直接“去掉”了“弱類型”特性可以看出,HHVM并不喜歡“弱類型”特性。然而,在我們很多PHP程序員的眼中,這卻是PHP的重要優(yōu)點之一。PHP里的變量被設(shè)計得隨性和飄逸,海納百川,一切皆可包容,不是讓語言顯得更為簡單嗎?
實際上,有些人認(rèn)為它是個嚴(yán)重的問題,對于“弱類型”的批評觀點大致如下:
在“嚴(yán)謹(jǐn)”的語言中,通常是預(yù)先定義好一個變量的類型,自始至終,變量的類型是固定的,使用范圍也是固定。而PHP的變量,通常我們只能看見它名字,類型大部分都不可以預(yù)先定義,并且還可以隨意改變。(內(nèi)存分配不好管理)
為了兼容弱類型特性,PHP需要實現(xiàn)大量兼容代碼,包括類型判斷、類型轉(zhuǎn)換、存儲方式等,增加了語言內(nèi)部的復(fù)雜度。(執(zhí)行效率低下)
變量的類型是不可控的,在執(zhí)行過程中存在大量的“隱性類型轉(zhuǎn)換”,容易產(chǎn)生不可預(yù)知的結(jié)果。(這里的確需要強調(diào),PHP的類型轉(zhuǎn)換是個必須掌握的點,各種類型的互相轉(zhuǎn)換的可能會產(chǎn)生很多問題,尤其是初學(xué)PHP的同學(xué)哈)
他們認(rèn)為,這些都不符合“所見即所得”的簡單性,而語法嚴(yán)謹(jǐn)?shù)恼Z言更高效率,也更容易“理解”。
受到類似批評的還有Javascript等語言,因為它在這個問題上的表現(xiàn)是一樣的。但是,一門語言最終被大規(guī)模使用,必然有它們的道理。PHP成為Web服務(wù)開發(fā)的首選腳本語言,Javascript則直接稱霸Web前端領(lǐng)域,能走到這一步都不可能是偶然因素,開發(fā)者們用腳投票選擇了它們。編程語言是人類和機器溝通的橋梁,終極追求是實現(xiàn)“人人皆可編程”的宏偉目標(biāo)。
縱觀語言發(fā)展歷史,從0和1的機器碼開始,到匯編語言,然后到C語言,再到動態(tài)腳本語言PHP。執(zhí)行效率呈指數(shù)下降,但是,學(xué)習(xí)門檻也呈指數(shù)降低。PHP語言不僅屏蔽了C的內(nèi)存管理和指針的復(fù)雜性,而且更進(jìn)一步屏蔽了變量類型的復(fù)雜性。提升了項目開發(fā)的效率,降低了學(xué)習(xí)的門檻,但同時犧牲了一定的執(zhí)行性能。然后,HHVM的Hack給我們一種“回歸原始”的感覺,重新引入了變量的復(fù)雜性。當(dāng)然,不同的語言解決不同場景下的問題,并不能夠一概而論。
小結(jié)
HHVM對PHP的性能提升,讓人眼前一亮,而磨刀霍霍的PHP7則讓人萬分期待。兩者都是極其優(yōu)秀的開源項目,都在不斷前進(jìn)和發(fā)展中。就目前而言,因為距離PHP7正式版的發(fā)布還有比較長的一段時間,所以當(dāng)前性能優(yōu)化方案的首選當(dāng)然是HHVM。不過,就我個人而言,我比較看好PHP7,因為它更能做到PHP代碼的向下兼容。如果兩者性能相差不大,我會選擇簡單的那個。
以上就是PHP7和HHVM的性能詳細(xì)介紹(圖文)的詳細(xì)內(nèi)容,更多請關(guān)注 其它相關(guān)文章!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。
新聞熱點
疑難解答
圖片精選