如何看待將Python代碼轉換成Go代碼並進一步編譯的 Grumpy 項目?
RT.
項目地址: google/grumpy
說明我大油管的Python codebase到了病急亂投醫的程度了?—— by 還在加班調bug的YouTuber.
Grumpy是針對YouTube的特定問題的。假設你有一大坨有年頭的Python 2 web serving代碼,結構錯綜複雜沒法拆也沒法挪;明顯的計算瓶頸已經優化掉了 —— 換成C extension或者像模板引擎預編譯 https://github.com/youtube/spitfire 這種特定優化,但性能還是一坨[1];GIL 沒法擴展只好做成多進程模型,但是你家大部分代碼不僅是C++還都假定單進程多線程一言不合就給你載入個全局靜態表。你會怎麼辦?
我去年看到Grumpy的計劃而且確定人家是認真的之後的第一反應是:are you OK? 不過仔細想想,非常樂觀的預計,如果Grumpy在單線程計算上能跟CPython持平,編譯器支持部分代碼能通過type annotation免除動態類型開銷,用goroutine代替多進程(因為代碼本來就在多進程單線程環境下所以運行時不用考慮支持GIL語義),用上Go非常靠譜的標準庫尤其是網路庫,一些廣泛使用的基礎庫如protobuf也可以換成Go版本(雖然Go的protobuf依然性能感人),某些流程改寫成Go比寫C extension更輕鬆,好像前途也挺光明的樣子。不過就像文檔里再三說明的,現在的實現遠還沒有到能在YouTube production使用,但如果這個嘗試最終成功了,能幫助到其他有類似情況的項目,如果有類似情況的項目的話,那個,祝福你……
好吧寫完這麼一篇我那幾千個unittests還沒跑完……
[1] Google其他很多伺服器模塊都是這樣,因為過分複雜,整體沒有明顯的性能瓶頸但跑起來還是渣 http://www.eecs.harvard.edu/~skanev/papers/isca15wsc.pdf明確聲明了的,以及可以預見到的與 CPython 的區別有:
1,不會完全兼容現在 Python 的全部特性,比如 eval 語句。這點沒有辦法,因為是 AOT 編譯器,運行時生成代碼只能放棄了。其實硬要支持也是可以的,現在 Go 要支持 Plugin 了,不過意義不大。
2,不會兼容現有 CAPI,也就是現有「原生擴展」都不打算支持了。我覺得是個好事,Python CAPI 設計的與 CPython 實現耦合性太強,比如會直接依賴內存對象布局,還需要使用引用計數來管理內存,想要完全兼容會是個大坑,並且也會成為性能優化的阻礙。
3,不支持原生 threading 了,而是採用 goroutine 來實現。這樣又會導致一系列與 CPython 的不兼容。但是好處是不會再有 GIL 了(有「GIL 情節」的同學應該會很開心),單進程可以跑到多核上了。
4,復用 Go 的 GC 機制。Go 的 GC 一直在進行改進,並且進步明顯,Grumpy 能夠坐享其成,何樂不為?
5,單純從(計算)性能角度出發,相對 CPython 應該不會有數量級上的提升。應該比不過現在的 PyPy / Pyston,畢竟動態性強的語言,做 AOT 的話很難獲得對象類型相關信息,沒有辦法在編譯時做優化。其實現在 Python 社區已經有很多 AOT 的方案了,比較常用的有 Cython,簡單理解的話,可以認為是把 Python 代碼編譯成對應的 C 代碼 + CAPI 調用,內存里的數據都還是 PyObject*。
6,IO 操作都是用 go 的標準庫來實現的。也就是說所有 IO 操作都是「天生非同步」的,相當於自帶 gevent monkey patch,做網路服務性能應該很強勁。
-------------------------------------------------------------------------------------
雖然項目 README 說 「intended
to be a near drop in replacement for CPython 2.7」,不過我覺得大家別想的太好了,大部分現有代碼應該都兼容不了的,numpy 什麼的不要想了,除非自己重頭實現一遍。
我的感覺是,這個項目立項目的就不是做一個 「drop in replacement」的 Python,而是一個可以用來實現高並發網路服務的「Python 方言」。
要想寫的爽,又不想擔心性能問題的同學,還是多嘗試 PyPy 吧,相對已經很成熟了,另外還可以關注一下 dropbox/pyston,目標真的是一個「drop in replacement python」。同事試了試同樣遞歸版的斐波那契。。。還沒cpy跑得快
這東西看起來並不是一個通用的Python實現,不支持C擴展就可以把好多Python庫給擋在門外了,甚至標準庫的好多東西都沒法用(sqlite, gzip, cPickle, hashlib..etc)。
考慮這個項目的背景,猜測一下就是想用Go把API layer那一塊給替換掉,無奈Python的codebase實在太大,一次性重寫不現實,所以就準備用這個東西把整個codebase先用Go跑起來,代碼還是在Python裡面開發,然後在慢慢一個一個的換成native的go。
所以對於這個項目是否會實現Python所有的功能表示懷疑。內部使用的話可以限制可以調用的庫和禁用某些feature來達到兼容的目的,但是作為一個通用的實現卻必須要去支持邊邊角角的功能。py的性能來自於它的動態性,並不是aot編譯轉一下就有很大提升,我在git上的larva-lang是在py語法基礎上去了很多特性來提效率的(larva是編譯為java執行),如果直接轉,像cython如果不加rex語法,只是去掉了解釋器循環執行位元組碼的過程,提速非常有限,當然我不清楚這個項目轉go是不是做了運行時編譯優化,效率方面只能說這裡因為我是做了動態類型語言轉靜態類型的(上面說的larva轉java),其實我也做了larva轉go,但性能渣很多,因為用go的語法實現動態類型的類型系統有些曲折,而且由於實現多態要interface,這玩意的性能。。。當然也可能我go不精
其它的從我個人經驗看,runtime和lib的構建也不是那麼容易的,很繁雜
larva的兩個版本都在git,一個是larva-lang,另一個是larva-lang_4j不管到底會不會有人用,怎麼說這都是一個測試編譯器的好方法。最近給GacUI做的腳本轉C++的事情(其實那東西從一開始設計出來就是為了最終變成C++),實際上就是等於把編譯器後端寫了兩遍,一遍出bytecode,一遍出C++。這中間隔了三年,所以不會受到當年寫輸出bytecode的時候腦子裡的記憶的干擾。因此寫完之後一比,每一個代碼的形狀長得不一樣的地方,都代表有一個bug。而且到底是哪邊的bug很容易看,畢竟VC++身經百戰,運行結果有不一樣的肯定是我自己弄錯了。
不看好,基於以下原因:
1、Python2已經要死了,2020年就不再更新了,目前來看Grumpy只支持Python 2。
2、不兼容現有的CPython的CFFI,這個就非常坑了。社區是否活躍是一個語言/框架/系統是否成功的重要因素,如果Grumpy要求別人拋棄所有的寫好的庫,如果自己推廣不利的話,沒人願意給他們補這一塊,就只能自己寫了,這樣的話要麼場景有限,要麼花費精力在這個上面。
3、即使只是為了性能,我並不覺得Python 3 + asyncio會比Python 2 + Grumpy有數量級上的差距。不要提Channel比Async/Await更好看更清晰,並沒有什麼優劣之分。既然這樣,為啥不遷移到Python 3而要去因為2重寫一堆Grumpy不兼容的C extension呢?我司最近就在遷移Python 3,已經接近完成,常見的坑就那麼幾個(Unicode你好)。在大家都再往Python 3遷移的時候,Grumpy突然給Python 2強行續一秒,不知道能挺多久。
4、我覺得這個東西是YouTube為自己量身定做的一個加速他們巨大的一坨legacy的Python 2代碼的方法,給別人當作全新的運行時來用只是一個副業。所以要開源出來給大家維護,來讓大家應用到自己的Use case上。一般的公司沒有Google的代碼規模,並不一定需要用它才能達到最佳的效果。
不過有嘗試總是好的,現在也沒看到具體實現的細節,百花齊放有利於社區的發展。
這個和russ Cox之前寫的 rsc/c2go 在某種程度上有相似之處。
c2go是將Go 1.4的c實現自動翻譯為Go 1.5的Go實現,完成自舉。實現了c的子集,並且有一些局限性,不具有通用性;
Grumpy想利用Go的運行時,讓python代碼也能利用上Go的並發特性以及高性能。是youtube開發人員對舊有的python2代碼的改進做出的一次嘗試。各種評估(用python3重寫;用Go重寫;繼續改進cpython,使用pypy等等,各種方法)之後,選擇了開發一個Grumpy出來。目前來看,用例也很特殊,符合youtube自身的需要,通用性不夠。未來這個項目怎麼發展還不好說,不過可以大膽預測一下:
以java以及圍繞jvm生態而產生出的其他編程語言為例,作為前車之鑒,可以很好的說明這個問題:java 8之前,java啰嗦,笨重,以及一些讓人難以忍受的地方(大量的ioexception,nullpointerexception等等),於是出現了一大堆庫(比如guava),和其他jvm上的編程語言比如(scala,groovy,clojure),都在不同層面上著力解決java的各種問題。但java 8出現了,雖然還是不夠,但已經讓很多人決定繼續留著java的懷抱中。9,10也會陸陸續續的到來。類似的,還有facebook的hack之於php。python3已經發布多年,成功與失敗暫且不論,改進相比python2有多大呢?我個人的看法是不夠大。python4也已經上了議程,pypy等等其他的項目也在繼續的開發中,所以:
如果未來python4或者其他python生態體系內相關的項目會有大的改進,那麼Grumpy會最終消亡;
如果這個自python2以來的問題在4以及pypy等其他項目中依然得不到改善,而Grumpy變得更加通用(比如支持python3,支持更多的python語法特性等等),那麼Grumpy會在python生態體系中成為重要一員的。相比jython,ironpython,cpython,Grumpy可以說是正好擊中了python的痛點。jython,ironpython沒有解決什麼實質性的問題,cpython倒是很重要,因為python體系裡面充斥著大量c語言寫的api庫。但Go代替c來寫這個恰好是Go的強項,需要的只是時間。有點先有雞還是先有蛋的意思。還有一種情況,Grumpy最終會變成下一個GWT,不會死但成為內部項目,內部使用,外部世界用的很少。
google會不會棄坑?
1.只要它還在繼續使用python,不打算徹底放棄使用python;2.就像上面說的,python自身的問題沒有得到解決以前。youtube總得運行下去,不能停機吧。最終,還是得看python自己發展的情況。沒仔細看過源代碼,只瀏覽了一下文檔,從結論開始說,沒有JIT,我覺得沒戲。Python慢的源頭之一在於動態特性在運行時實現裡面引入的那一堆__dict__,這個沒有JIT的情況下你用什麼語言實現都去不掉,讓程序員自己全重寫成__slots__不如讓他們去死。缺點拿來之後,monkey patch之類的優點又沒了(Go的語言特性連decorator都支持不了),這是取了兩者缺點的綜合。Go寫的就快了?Cython還能編譯成C呢,不改源代碼一樣很慢,充分說明慢的根源甚至都不是解釋執行。
看到這個項目, 感覺還是很贊的.
應該是2017年, 開年 Python 社區最大利好消息.
項目是 Google 的 Youtube 團隊開源的.
項目地址: https://github.com/google/grumpy
項目貢獻者在 Hacker News 上的討論:
1. 項目初衷: 把 Python 源碼翻譯成 golang 代碼, 再編譯成機器碼, 再執行, 提升性能. Grumpy 沒有虛擬機(VM). 編譯好的 Go 源碼是對 Grumpy 運行時的一系列調用, 一個Go庫服務於具有相似目的的Python C API(儘管不直接支持C API).
2. 項目目前只支持 Python2.7, 未來可能支持 Python3(估計要很久很久...)
3. 目前對 Python 標準庫不完善, 不支持 c 擴展.
4. 關於是否已上線? 答:目前有很多不完善, 暫未在 Youtube 上線.
5. 關於為何不用 go 重寫 Python 模塊, 答: 基於 Python 的代碼量龐大, 重寫代價高過寫一個新的運行時.
6. 關於此項目是不是臨時過渡項目, 為了向 go 遷移? 答: 不是.會繼續寫 Python.(估計他們團隊更喜歡寫 Python 吧)
項目吸引人的特性:
1. 解決令人詬病的 Python 性能問題. 對社區是重大利好.
2. 該項目支持在 Python 源碼中 import Go 的庫, 這... 有太多想像空間
3. 該項目支持在 Golang 源碼中 import Python 的庫, 這... 想像+Max
誰值得關注:
1. 寫 Python 的同學, 想想既可以寫的爽, 再也不擔心性能問題了(美好願景). 這是要裝逼飛起的節奏. 忽悠領導支持, 又多了一項理由.2333
2. 寫 Golang 的同學, 想想平白多了很多 Python 的 lib 可以用, 是不是有點小雞凍.
3. 同時寫 py, go 的同學, 多了一項新選擇. 雖然寫 go 也挺流暢, 但那要看跟誰比, 跟 java 比是沒問題.
Hacker News 摘錄討論:
展望:
2017年, Python3.6的普及, 任重道遠. 3.6有很多吸引人的特性.
從內心深處, 不應該再繼續寫2.7, 但看看第三方 lib, 總有幾個 lib 限制你不得不停留在2.7上.
大家都主動遷移吧.
Grumpy 這個項目很贊, 應該可以引起 Python 和 Golang 兩大社區開發者的注意.
有個好爹也很重要, github 的 star 蹭蹭的漲.
關於該項目的討論:
官方博客:
https://opensource.googleblog.com/2017/01/grumpy-go-running-python.html
hacker news 討論(大量乾貨):
https://news.ycombinator.com/item?id=13319904
reddit 討論:
https://www.reddit.com/r/programming/comments/5m0np2/grumpy_go_running_python_by_google/
(知乎新版本編輯器更屎了, 媽蛋, web 版編輯完, 手機版顯示成屎.)
好氣啊。當初我花了一個月的功夫,把我GitHub上所有的Python項目都用Go重構了一遍,結果你就告訴我有了這個(*_*;不過我相信grumpy的效率肯定還是比不上原生庫,恩(自我欺騙中
潑盆冷水,你們還記得大明湖畔的pypy,jython和ironpython嗎
大量python庫是用c寫的,拋棄了cpython api的兼容就等於拋棄了python最大的優勢,希望能發展起來,但是並不看好剛我看見是google團隊弄出來的 我就一直有種這個項目吃棗藥丸的感覺
跟py3搶py2的生意
py那群人實在是太頑固保守了。
剛剛看了Zhengyis Blog ~ (Python)使用Grumpy將Python源碼轉換成Go ,感覺這個項目潛力很大。
如果你還知道曾經有一個叫GWT的Java 轉Javascript的項目,那你最好遠離Grumpy。
把一個語言轉換為另一個語言來運行的項目都藥丸
推薦閱讀:
※基於ArcGIS的python編程:2.python基礎(一)
※不再寫 for 循環
※翻譯|Stack Overflow上關於Python的高票問答(一)
※Python基礎語法知識總結與實踐(二)
※聊聊Python,談談未來