如何看待微軟 Pyjion 的進展以及 CPython 性能優化的未來?

微軟Pyjion自項目開始以來時間不長,但是Github上已經有兩個月沒有任何提交,不知道是不是已經掛了。在Perf目錄下的README.md文件里有最新的benchmarks結果,顯示加了jit後,很多benchmark性能反而下降了,有的甚至慢4倍以上。

在Unladen Swallow, Psyco, Pyjion(?)等等項目的眾多大牛們對CPython JIT的嘗試均告失敗後,我們究竟應該如何看待CPython性能優化的未來?


Pyjion還沒死。Brett和Dino大大本來開Pyjion項目就是自己在業餘時間搞的,而不是微軟正式立項全力支持的項目,所以他倆一忙正經工作就不得不減少對Pyjion的投入這個是最初大家都知道的事。

背景介紹:[新聞] CPython / 微軟 Pyjion / IBM Python+OMR - 編程語言與高級語言虛擬機雜談(仮) - 知乎專欄

他們現在最關注的是PEP 523 -- Adding a frame evaluation API to CPython。這其實才是Pyjion對CPython影響最大的部分,是Pyjion項目最核心的目標——給CPython添加API,讓它支持插入JIT編譯器。

Pyjion的目標:

  1. Add a C API to CPython for plugging in a JIT

  2. Develop a JIT module using CoreCLR utilizing the C API mentioned in goal #1

  3. Develop a C++ framework that any JIT targetting the API in goal #1 can use to make development easier

這裡面#1是最重要的,而#2目前的形態只是為了驗證#1的效果,並且有一個實際實現來說服CPython社區這是現實可行的而不是空想。

PEP 523就是目標#1目前的形態。Brett和Dino在與CPython社區以及其它Python實現團隊討論之後,發現他們原本想提議的那個JIT編譯器API太具體了,限制了應用場景,感興趣的人不多;同時他們發現其實只要一個更簡單的鉤子就足以讓JIT編譯器能掛進來,這也就是現在的PEP 523。

原本目標#1所想像的API的一部分會挪到目標#3里去,作為可插入的JIT編譯器的框架的一部分,而不是作為CPython內建的一部分。

Pyjion目前的實現還非常簡單,特別是在觸發編譯的地方做得還很粗糙。這塊正是非常影響JIT編譯器對整體運行性能的地方。JIT編譯畢竟是一個運行時行為,有相應的開銷,如果一個程序運行的時間太短,則JIT編譯帶來的性能提升可能無法彌補其所帶來的開銷,總體結果就是變得更慢了。

在其它成熟的託管運行時上,這種問題有許多現成的解決方案。至少,要解決題主說的「加了JIT比不加還慢」的問題是有很現成的做法的。

其一是後台編譯(background compilation),允許解釋器在觸發編譯後繼續解釋執行程序,而被觸發的JIT編譯則在後台並發編譯,這樣就可以最大限度減少JIT編譯對程序的初始性能的負面影響。Pyjion目前的實現用的是阻塞式前台編譯(blocking compilation / foreground compilation),也就是當解釋器觸發JIT編譯後,解釋器要停下來等,直到JIT編譯完成後再跳到編譯好的代碼里去執行。這對許多小程序來說都太慢了。

其二是多層編譯(tiered compilation),讓代碼隨著被執行次數的增加2而漸漸被更高優化層級的編譯器所編譯。Pyjion目前只有解釋器和一級JIT編譯器,所有JIT編譯都用同樣的優化層級,對只執行比較少次數的代碼來說可能會帶來過多的編譯開銷,而對執行次數很多的代碼來說可能沒有投入足夠編譯優化。

其三是並行編譯(parallel compilation),開多個線程來同時並行編譯多個函數。

以成熟的JVM——HotSpot VM為例,上述3種技巧都用上了,效果很好。

順帶放個傳送門吧:為什麼 JVM 不用 JIT 全程編譯? - RednaxelaFX 的回答

這些都是屬於Pyjion的目標#2的問題。上面也說了,Pyjion目前的目標#2其實只是玩票性質的,並不是他們想要做的最終形態。它目前存在的目的就是告訴大家這個JIT是真的可行的,是完全兼容CPython 3.5的,並且在一些運行時間較長的場景里能展現出性能提升。

要提升它的啟動性能,只要投入開發資源去打磨打磨JIT的觸發方式就能看到顯著效果,只是目前暫時還沒到那一步而已。

(思路之一:讓一個Python函數執行多次(例如10次、100次)之後再觸發JIT編譯,並且支持後台編譯與並行編譯)

=======================================

至於題主問的:

在Unladen Swallow, Psyco, Pyjion(?)等等項目的眾多大牛們對CPython JIT的嘗試均告失敗後,我們究竟應該如何看待CPython性能優化的未來?

這個回頭再補充…但一言以蔽之:受制於CPython所堅持要保持兼容的C API,CPython的性能優化的天花板太低了。添加JIT編譯器能夠提升性能,但提升空間非常有限,因為runtime里的額外開銷太多了。

放個傳送門佔位:Pyjion的代碼質量一例 [20160221] - 編程語言與高級語言虛擬機雜談(仮) - 知乎專欄

=======================================

有別的回答提到Dropbox的Pyston。這個項目其實現在處於很微妙的狀態…(咳咳

正好我以前的經理現在在Dropbox做經理,也會管到Pyston,最近跟他聊的時候聽說他們在考慮大幅改變Pyston的開發方向。不知道最後能不能招到人去做這件事呢。

技術問題除外,Pyston要面臨的最大問題恐怕就是隨著Dropbox越來越多代碼轉為用Go實現,優化Python自身性能的迫切性越來越低了。而優化Go的性能變成了新的熱點。如何分配開發資源就成了個有趣的問題。——一手小道消息。


儘管我無比期望Python執行效率能有質的提高,但是好像目前看來似乎我用到Python的地方,其實效率問題反倒不是什麼太大的問題。其實說真的,很多使用者甚至根本輪不到他們去抱怨Python的性能問題,他們的很多所謂效率問題,恐怕一開始就是演算法、數據結構選用的問題。演算法的優化如果已經到了極限,只能寄希望於堆硬體拼解釋器的應用場景,我暫時沒有怎麼遇到……如果遇到了,我可能更寄希望於再加兩台機器……

然後說JIT。目前看來,要說完成度最高的那是pypy,但是這貨的C-API與CPython不一樣,於是乎大把的C擴展往往不能用或者慢得很。如果我沒記錯,Pyjion的賣點在於完全兼容CPython,它的JIT更類似於把代碼拆開,該CPython跑的還是在個CPython運行時里跑,性能提高本就十分有限。早就可以預測Pyjion的效率高不到哪兒去,畢竟做法特別保守,以保證CPython一致性為第一目標的,又是試驗階段,慢點兒完全可以理解。總之CoreCLR上有個Python環境不也是挺好的么?

此外,真要說效率的話,pypy和pyston都做到了超越現有cpython的能力,從這一點來看,前路並不暗淡啊……


@Coldwings 關於python性能是不是問題的說法,我覺得這要看應用場景,比如某些應用中腳本邏輯非常複雜,而且對單節點承載能力是有要求的,並不都可以通過加機器解決問題。題主自己的項目中就遇到了python單節點性能瓶頸。不過這是題外話了。

另一方面,pypy等實現雖好,但畢竟不是基於CPython,從CPython的API設計來看,脫離CPython的實現要完美兼容現有代碼庫並不現實。因此在工程應用上一般也不會考慮它們。

另外糾正一個小錯誤: )Pyjion並沒有打算像IronPython一樣運行在CLR上面,而只是把CLR里的jit compiler用於CPython。

題主仍然對CPython的性能保持關注並抱有幻想……


不是很懂,但是不知為啥,我的IronPython不能調用第三方庫,直接把IDEL的sys.path複製過去都沒用,所以一直感覺微軟的py支持很迷。


起碼,pypy 是會一直活下去的。

還有 dropbox 的 pyston 還活著。


推薦閱讀:

安卓運行Python的神器:QPython
Python中你可能不知道的platform
Kaggle HousePrice : LB 0.11666(前15%), 用搭積木的方式(2.實踐-特徵工程部分)
八大排序演算法python實現合輯
[Python + SQL] NBA史上最弱的球隊是哪一個

TAG:編程語言 | Python | 即時編譯JIT |