如何使用python語言而辯論

    幾分鐘以後有人問我Python的用法(usage),而這篇文章沒有說起,但倒是一個讓人深思的問題。咱們看到,使用Python的用戶極可能在將來保持高位,可是Python是否會被用到儘量多的項目中是不能保證的;用戶(users)數目不少並且穩定,可是項目中Python的用處(use)並不肯定。

    這篇文章的用意是幫助代表Python仍然對大多數軟件項目是切實可行的。我不擔憂把Python推銷給反對其餘動態語言(如Ruby)的人,由於我認爲這些爭論與我的喜愛有關。這篇文章是講給那些推銷靜態類型語言的人。具體上,這篇文章是針對Go的,但也能夠是其餘任何靜態類型語言。

」爲何Go?」,你可能會問。由於Go實際上在獲取Python的用戶。當2003到2005年間Python的增加曲線是個曲棍球棒時,Python還不是被推下山巔的王者,而是個弱者。傳統上,Python從Java之類的語言陣營中得到用戶,而且留住了他們(我不想談C++用戶,由於一般他們有嚴格的性能需求,須要一個系統語言,或者是性能成癮者,而且須要好好恢復)。可是Go的狀況不太同樣。現在Python是使用最多的語言之一,而再也不是弱者了。一旦在靜態類型語言社區中出現一門語言,它的生產效率/性能的取捨至關好,那便足以說服一些Python的程序員選擇Go而再也不是Python了。

現在的Go

首先我應該說,Go是目前我第二喜歡的語言。若是今天我要啓動一個項目,但不能說服人們使用Python,那我會提議使用Go。不要誤解我在本文中說Go是門很差的語言。這篇文章的要點是說服其餘人,Python是生產率/性能取捨遊戲中Go以外切實可行的替代方案,而不是表達Go是門很差的語言。認爲這篇文章是反Go的,那就是你的我的想法,並且不該該這樣認爲。

我應該說,我偶爾在工做中使用Go,並有點想關注這門語言的社區。既然我不能僅憑想象就成爲Go專家,但這番話並非僅從文檔或者博客中提取出來的。可是因爲我是Python開發團隊的一份子,不管我如何試圖表現得公平,固有的偏見某種程度上仍是有的。

那麼,帶着這些警告,咱們來看下Go提供給開發者什麼。

生產率

我看待Go的方式是,使用你最喜歡的編程語言,移除那些難於加速生產率的特性,就是Go。靜態類型的影響被降到最小,由於一般只有在API邊界時你纔會面對它。結構類型一樣使事情變得簡單(把它認爲是鴨子類型)。語法並不笨拙(雖然它使用了花括號)。不要認爲Go是C/C++去掉不安全的特性,加上生產率更高的東西,否則你會很失望(好比,「爲何我不能使用make()內置函數,也不能像map類型同樣對返回值進行計數」,這種看待Go的方式是錯誤的;這就是爲何C++開發者沒有轉到Go的緣由)。快速編譯也使開發週期更像一個動態語言,而不是一個須要編譯的語言。並且事實上有些人喜歡沒有異常機制帶來的冗長,由於這促使你處理每種異常情形而不是(意外地)忽略它們(這是貫穿Go初始系統語言設計的實例)。還有,這門語言自己至關短小易記,並有嚴格的前向兼容性要求(forward-compatibility requirements)(你不可能更快地得到泛型),大致上使用Go來編碼是件很愉快的事情。

因爲是靜態類型,Go能夠很容易地得到工具支持(它對以前以此爲設計目標的語言也有幫助)。Go確保核心工具跟隨Go自己提供,也是明智之舉。go fmt強制執行Go風格的規則,並容許經過用戶自定義的規則來重構代碼(「採用製表符縮進」再也不是問題,由於這意味着你能夠爲所欲爲地設置編輯器來表明製表符,而後go fmt將其轉換爲普通製表符以適用VCS)。go fix會更新代碼以跟最新發布的版本保持一致。go get獲取依賴並安裝。

Go最後一個生產率功能是它靜態編譯全部東西,使部署更簡單。若是你使用容器來開發和部署,這也不算什麼。只有當你發佈單個文件的命令行工具,而不是一組依賴和你本身的代碼時,這纔算得上事。

性能

就性能來講,Go作的很好。很難指出任何基準能準確的證實Go老是最快的選擇,甚至計算機語言基準遊戲中一些基準證實CPython 3是最快的。可是一般狀況下能夠認爲對於你的任何工做來講Go已經足夠快了。

Go真正出色的地方是併發性(concurrency) 。要注意併發代碼並非一般誤解的並行(parallelized)代碼; 併發代碼仍然能夠是單線程的,僅僅在任務切換方面更加簡單/出色。Go經過使用goroutine使連續併發的代碼執行起來絕對的簡單。若是你不想使用共享內存的方式(雖然也一樣支持),該語言提供的通訊管道容許以很是簡潔的消息傳遞方式進行併發編程。將全部特徵整合進此語言中成爲儘量使用該語言開發併發代碼的又一緣由。換句話說,Go程序運行很快,該語言盡力使你在合理的方式上得到該效果。

現在的Python

若是順利的話我已經讓你相信Go是一種優秀的編程語言,除非由於其餘緣由,一些人不會認爲我在整篇文章對Go的描述很糟糕。如今咱們討論一下Python的生產率/性能是怎麼樣的。

生產率

首先也是最重要的,Python很是容易學習。這也是爲何在當前高評價的美國大學中將Python做爲首選的教學語言 。這至關於該語言擁有成熟穩定的新程序員的來源以及更容易培訓其餘程序員。 我想,要說服別人只用幾行Python代碼就會完成不少工做這並不難(Go/Python 3比較 顯示Python每次都比Go使用更少的代碼完成相同的工做)。因此我會堅持認爲使用Python會更高產,即便和Go相比,這不會有人反對。

一般你們反對Python的地方是在工具支持方面。可是若是你注意到我指出的Go相關的支持工具,fmt, fix, 和 get, Python社區也有對等的工具。對遵循PEP 8的風格格式化(style formating), 能夠在提交檢查時使用pep8,或者若是想要更多go fmt風格的自動重寫可使用autopep8。對用於重構的go fix或go fmt,你能夠說2to3也能夠完成一樣的功能。對於go get, Python有pip。咱們有venv/virtualenv或cx_Freeze這樣的代碼凍結工具(跟其餘同樣,位於容器之上?on top of containerization like anything else),而不是靜態編譯的二進制包。甚至有貫穿項目的代碼分析工具如pylint。說Python由於缺乏工具支持而不能用於大型項目,這種觀點對我來講是很膚淺的。

若是說有哪方面Python徹底作的好,那就必定是它豐富的第三方擴展庫和相應的工具可供使用,就像在PyPI上面看到的那樣(我相信確定有人忍不住要爭論說,「並非全部的第三方庫都可以在Python3上面運行啊」,事實確實如此,然而,這些第三方擴展庫對Python3的支持已經至關好了,並且還在繼續改善中,因此我不會太在乎這個爭論,另外,你能夠同時使用Python2/3兩個版本進行編碼,不須要關心針對哪一個版本)。看一下godoc.org,上面顯示Go也並不缺乏社區支持,Pytho之因此可以擁有更多可用的第三方庫僅僅是由於它的年齡,這個狀態也會繼續持續。

性能

由於Python已經存在好久,且變得如此龐大, 簡單地去說 「Python是足夠快的」 不能說明整個的狀況, 那是由於有各類各樣的實現加速的方式。可是在深刻到VM級別的選項以後,意味着Python的stdlib提供了得到加速的選項。舉例來講, concurrent.futures 是尷尬地執行並行代碼的方式,這種方式是極其簡單的。而在Python 3.3中,新的asyncio編寫了異步代碼。它沒有像Go那樣被集成進語言,在Python中的併發程序設計是可行的,且在方式上也未必是那麼痛苦的。

可是最好的辦法是,你能夠在選擇的VM裏改變Python代碼的性能。

CPython + Cython

若是你在使用 C 拓展模塊,CPython 就會使你最好的選擇(可能你不知道這個術語,CPython 是你能夠在 python.org 得到的解釋器)。對大多數的狀況而言性能至少合理些– 由於某些緣由,一些人認爲Python 開發團隊不關心性能,這個一個謊話 – 並且即將會成爲新的特性,由於 CPython 同時擔當着語言規範的做用。

若是認爲你的一些內循環代碼確實須要提升些速度, Cython 是 CPython 的選擇。Cython 會盡量的將你的 Python 代碼編譯成 C 拓展代碼。有若干種支持的方法能夠產生更好的 C 代碼,因此這取決於你須要怎樣的 Cython 特性。Cython 同時也使寫出 C 拓展模塊更加簡單(但要繼續讀下去,除了CPython 還有其餘的選擇)。

PyPy + cffi

若是你不依賴於已存在的 C 拓展模塊,PyPy 會給你提供整體上最好的性能。它的JIT很是好並且它的團隊歡迎受到使用 CPython 而且運行更快的代碼的挑戰,由於他們痛恨在 speed.pypy.org 中顯示的那麼慢。實話說,除非PyPy不支持你真的想用的那個版本的 Python – 由於 PyPy 確實會落後2個版本, 好比pypy3 如今支持 Python 3.2 然而 3.4 是最新的 CPython 發佈版; 它們期盼在這個問題上能獲得幫助(donation) – 我只能考慮不使用PyPy由於你依賴於已存在的C拓展模塊C( numpy 是最多見的問題,雖然 PyPy is looking for donations 可修復這個問題)。

但這不意味着,若是你想封裝一些C代碼就用不了PyPy。PyPy項目還有另一個子項目cffi,這個項目的目的是使Python代碼也能夠利用封裝的C代碼。使用cffi的關鍵好處在於,一旦你使用了cffi,C代碼就能夠用於CPython和PyPy(我認爲IronPython和Jython也在添加對cffi的支持)。因此若是你在封裝C代碼,我強烈建議你看下cffi,而不是手動寫C擴展模塊或者使用Cython,這樣你有更好的Python實現的支持,還能使用PyPy。

Numba

若是你在作數值相關的工做,你確定應該考慮Numba這個選擇。在科學計算上,經濟學家注意到了它的性能。雖然在普通的Python編程上,它不能幫到什麼忙,可是若是在Python很是強大的科學計算棧中用到了numpy或者其餘模塊,Numba使用LLVM來進行JIT確定會有幫助。

將來的 Python

考慮到全部內容,Python確定不是停滯不前的(Go也沒有,好比它們都在忙於用Go重寫編譯器和將鏈接器之外的東西轉移進編譯器來得到更快的編譯速度)。Python 的將來看起來仍是光明的。

生產率

Python 是一種在進化的語言。不像 Go,Python 樂於改變該語言,甚至是以永遠再也不向後兼容的方式。這意味着Python會比Go更快的速度變得更加高效(雖然在Go 2開發以前Go的團隊對該語言進化持哪一種觀點仍是未知的)。

在工具方面,標準化的 函數註解 是爲了聲明類型。 這是在 PyCon 2014 語言峯會期間提出的,針對函數參數和返回值,裏面提到有大量的項目如今想要有一種聲明預期類型的方法,使用函數註解考慮到了在某些方面的標準化,最終可能對標準庫函數也會是有用的。在pytypedecl的郵件列表上的討論尚未開始,可是我知道PEP大概是要開始了。不只僅是對像Cython和Numba這樣的項目在什麼地方使用打印信息,還包括在諸如代碼分析,重構等的時候使用。

性能

長遠看來,有兩個項目能夠幫助提高Python的性能。一個是新的Python虛擬機Pyston。儘管Pyston剛出現時間不長,但它的目標是要使用LLVM的JIT(是的這不禁得讓人想起Unladen Swallow,然而LLVM的JIT已經比它在2009年時好不少了,因此這個項目仍是很有但願取得好效果的)。

其實PyPy-STM纔是真正可以讓我興奮的項目,」STM」表示」軟件事務性內存」,它基本上是容許Python丟棄GIL的。PyPy-STM此時的性能比PyPy要慢大約1.2-3倍,這樣的表現已經至關不錯了。目前他們正在尋找資助,來繼續這項工做,要實現這個目標:使得帶有兩個線程的PyPy-STM值得在PyPy上廣泛運行。

在黑暗中作出選擇

但願這篇博客傳達的不是一個總結, 而是一個關於生產力/性能折衷的方案。 Python已經清晰地擁有了強大的生產力輔助而且沒有哪一個領域表現不佳,這還是我選擇的語言。若是你發現本身有可能選擇Python項目之外的東西,請必定要停下來思考沒有使用Python所帶來的生產力損失,而後看看你有各類選項讓Python加快執行,這樣你再去作一個全面的關於Python是否能夠爲你的項目工做的選擇。python

相關文章
相關標籤/搜索