這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
一開始我以為是一篇2013年的老文章,沒想到竟然是2015年。不懂Python不要亂噴啊。你直接說“我不懂Python,我也不願意維護前任寫的糟糕代碼,我Go牛B,所以我要重構一遍!”我到覺得你智商正常點。。
我覺得go不錯,但是如果不是特定領域開發,沒有足夠多成熟穩定的庫仍然很麻煩的事情。
http://www.jianshu.com/p/afa14e631930
http://www.lupaworld.com/article-254456-1.html
python雖然很強大,但我們在使用的時候也碰到了一些問題,主要由如下幾個方面:
動態語言
python是一門動態強型別語言。但是,仍然可能出現int + string這樣的執行階段錯誤,因為對於一個變數,在寫代碼的時候,我們有時候很容易就忘記這個變數到底是啥類型的了(點評: 真的很少遇到, 每個函數的參數類型都有約定, 所以根本不會記不得)。
在python裡面,可以允許同名函數的出現,後一個函數會覆蓋前一個函數,有一次我們系統一個很嚴重的錯誤就是因為這個導致的。(點評:遇到過,不過這也是不遵循約定導致的,命名不規範的緣故,在不同模組採用相同的名稱是可以的,另外這個問題在靜態語言裡也有啊,你連結到一個錯誤的庫上。 在運行時用後一個函數會覆蓋前一個函數,這也正是monkey patch存在的基礎。雖然我覺得如果在語言層面上對使用者可以對變數的類型進行顯式聲明的約束很有用)
上面說到的這些,靜態語言在編譯的時候就能幫我們檢測出來,而不需要等到運行時出問題才知道。雖然我們有很完善的測試案例,但總有case遺漏的情況。所以每次出現執行階段錯誤,我心裡都想著如果能在編譯的時候就發現該多好。(點評: 有了編譯時間檢查運行時就不出錯了嗎? 難道代碼寫完了就完了嗎? 差不多每次添加功能或者調試的時候,讀到感覺寫的不好或者寫的不清楚的,都要做些清理,畢竟人對於所使用的庫或者語言的理解是逐步深入的。 )
效能
其實這個一直是很多人吐槽python的地方,但python有它適合乾的事情,硬是要用python進行一些高效能模組的開發,那也有點難為它了。
python的GIL導致無法真正的多線程,大家可能會說我用多進程不就完了。但如果一些計算需要涉及到多進程互動,進程之間的通訊開銷也是不得不考慮的。
無狀態的分散式處理使用多進程很方便,譬如處理http請求,我們就是在nginx後面掛載了200多個django server來處理http的,但這麼多個進程自然導致整體機器負載偏高。
但即使我們使用了多個django進程來處理http請求,對於一些超大量請求,python仍然處理不過來。所以我們使用openresty,將高頻次的http請求使用lua來實現。可這樣又導致使用兩種開發語言,而且一些邏輯還得寫兩份不同的代碼。(點評:不用django,沒有發言權,不過高頻的請求可以用Cython最佳化,現在的Cython已經比2013年的時候方便多了。。。)
非同步網路模型
tornado的網路模型是非同步,這意味著它不會出現django那樣因為外部服務不可用導致這個服務無法響應的問題。話說,比起django,我可是非常喜歡tornado的,小巧簡單,以前還寫過幾篇深入剖析tornado的文章了。雖然tornado是非同步,但是python的mysql庫都不支援非同步,這也就意味著如果我們在tornado裡面訪問資料庫,我們仍然可能面臨因為資料庫問題造成的整個服務不可用。(點評:曆史原因,幾乎所有Python的標準庫都是同步的,)
其實非同步模型最大的問題在於代碼邏輯的割裂,因為是事件觸發的,所以我們都是通過callback進行相關處理,於是代碼裡面就經常出現幹一件事情,傳一個callback,然後callback裡面又傳callback的情況,這樣的結果就是整個代碼邏輯非常混亂。python沒有原生的協程支援,雖然可以通過gevent,greenlet這種的上patch方式來支援協程,但畢竟更改了python源碼。另外,python的yield也可以進行簡單的協程類比,但畢竟不能跨堆棧,局限性很大,不知道3.x的版本有沒有改進。(點評: Python3.4引入asyncio,Python3.5引入的async和await,就算使用Twisted,也不會一堆callback啊。有沒有搞錯?不清楚跨堆棧)
開發營運部署
當我第一次使用python開發項目,我是沒成功安裝上項目需要的包的,光安裝成功mysql庫就弄了很久。後來,是一位同事將他整個python目錄打包給我用,我才能正常的將項目跑起來。話說,現在有了docker,是多麼讓人幸福的一件事情。(點評: 沒有用過虛擬Python環境?virtualenv,python直接調用mysql connector,怎麼會裝一堆庫?不明所以)
而部署python服務的時候,我們需要在伺服器上面安裝一堆的包,光是這一點就讓人很麻煩,雖然可以通過puppet,salt這些自動化工具解決部署問題,但相比而言,靜態編譯語言只用扔一個二進位檔案,可就方便太多了。( 點評:測試環境就是開發環境,你確定靜態編譯的不解決好依賴在別的機子上面就能跑?)
代碼失控
python非常靈活簡單,寫c幾十行代碼才能搞定的功能,python一行代碼沒準就能解決。但是太簡單,反而導致很多同學無法對代碼進行深層次的思考,對整個架構進行細緻的考量。來了一個需求,啪啪啪,鍵盤敲完開速實現,結果就是代碼越來越混亂,最終導致了整個項目代碼失控。
雖然這也有我們自身的原因,譬如沒好的代碼review機制,沒有好的項目規範,但個人感覺,如果一個程式員沒經過良好的編碼訓練,用python很容易就寫出爛的代碼,因為太自由了。
當然,我這裡並不是說用python無法進行大型項目的開發,豆瓣,dropbox都是很好的例子,只是在我們項目中,我們的python代碼失控了。(點評:好像沒有聽說用了那種語言代碼就不失控了,這根本就是拒絕小步重構,代碼模組化差,模組耦合度高等等一系列問題導致的,Python的實現代碼少,反而能夠有精力進行持續的快速改進。。)
上面提到的都是我們在實際項目中使用python遇到的問題,雖然最終都解決了,但是讓我愈發的覺得,隨著項目複雜度的增大,流量效能壓力的增大,python並不是一個很好的選擇。
(點評: Python存在問題嗎? 當然也有很多,比如
* 配套的非同步庫太少且缺乏維護。
* 不能限制變數的類型(雖然有Python3.5的type hints,但是和注釋沒啥區別)
* 本身的計算效能比V8引擎的JavaScript要差很多(可以藉助C)