Python 開發者在遷移到 Go(lang) 時須要知道哪些事?

【編者按】本文最先由 Repustate 發佈,主要介紹將代碼遷移至 Go(lang) 時的注意事項。文章系國內 ITOM 管理平臺 OneAPM 編譯呈現,如下爲正文。html

這是一篇講述將大塊 Python/Cython 代碼遷移到 Go 的長文章。若是你想了解整個事情的通過、背景等全部信息,請讀下去。若是你只對 Python 開發者須要瞭解的事感興趣,請下拉到早該知道的事板塊。python

背景

咱們在 Repustate 最大的技術成果就是實現了阿拉伯語情感分析。阿拉伯語是個難啃的硬骨頭,由於阿拉伯語詞彙的形式很是複雜。阿拉伯語的標記化(把一句話拆分紅單個單詞)也比英語要可貴多,由於阿拉伯單詞內部可能會包含空格(例如單詞內部「aleph」的位置)。在不泄露機密的狀況下,Repustate 利用支持向量機(SVM)來獲取一個句子最可能的意思,而且以此來推斷句子的情感。咱們一共採用了22種模型(22個支持向量機),文檔中的每一個詞都會被分析。也就是說,若是一個文檔包含500個詞,就會與支持向量機進行10000屢次對比。golang

Python

Repustate 幾乎徹底是用 Python 搭建的,咱們使用 Django 來搭建 API 接口和網站架構。所以,爲了保持代碼一致性,使用 Python 來實現全部阿拉伯語情感引擎才說得通。就原型設計和實現流程而言,Python 依然是一個很好的選擇:表現能力優秀,又有強大的第三方庫資源,等等。若是是服務於網頁,它就是最佳選擇。若是是稍低級別的運算,須要與哈希表(Python 中的字典)進行大量對比時,運行速度就會慢下來。咱們一秒鐘只能處理2到3個阿拉伯語單詞,這種速度太慢了。相比之下,咱們的英語情感引擎每秒能處理500個單詞。django

瓶頸

所以,咱們啓動了 Python 分析器,開始調查速度慢的緣由。還記得上文提到咱們有22個支持向量機,每一個單詞都會經過它們處理嗎?原來這個過程是按順序進行,而不是並行的。好了,第一個想法是換成相似分佈式計算系統(map/reduce)的處理器。長話短說:Python 不適合用 map/reduce。當你須要併發性的時候,Python 並不能幫上忙。在 Pycon 2013大會中,Guido 談到了 Tulip,他但願用來解決這個問題的一個新項目,可是還要過一段時間才能發佈。但是,若是已經有了更好的選擇,爲何還要苦等下去呢?編程

選擇 Golang 仍是回老家(Go Home)

在 Mozilla 的朋友告訴筆者,Mozilla 服務的日誌架構大部分代碼都已遷移到 Go,部分緣由是 goroutines 超級便利。Go 是由谷歌員工開發的,設計之初就將併發需求列爲一級理念,而不是像 Python 的衆多解決方案同樣在作過後補救。所以咱們開始着手實現從 Python 到 Go 的遷移。json

雖然 Go 代碼還沒實現大規模產出,獲得的結果已經很是振奮人心。咱們如今一秒鐘能處理1000個文檔,使用的內存大大減小,並且也不用再去調試和解決使用 Python 時會遇到的多進程/協程(gevent)/「爲何 Control-C 殺死了個人進程」等問題。數組

喜歡 Go 的緣由

任何略懂編程語言的人(明白解釋與編譯、動態與靜態區別)都會說:「哈,顯然 Go 要快多了。」沒錯,咱們是能夠用 Java 重寫全部內容,而且取得相似的效果,可是這並非 Go 勝出的緣由。你用 Go 寫的代碼彷佛一出來是正確的。筆者也說不清楚,可是不知怎麼的,一旦代碼被編譯(編譯過程很是迅速),你就會感受它能工做了(不僅是運行不出錯,並且還邏輯正確)。這聽起來很含糊,可是它是真的。在冗餘或無冗餘方面,它跟 Python 類似,它把函數當作一級對象,所以函數編程很方便。並且毋庸置疑,goroutines 和 channels 會讓你更加省心省力。靜態類型還會帶來極大的性能提高,以及更精確的內存分配控制,可是又不會損失太多表達性。數據結構

早該知道的事

除去溢美之詞,跟 Go 打交道須要與 Python 徹底不一樣的一套思惟模式。如下列出的是筆者在遷移時作的一些筆記——都是在從 Python 遷移到 Go 時隨機想到的一些東西:架構

  • 沒有內建的集合類型(須要使用 map,而後測試存在性)併發

  • 因爲沒有集合類型,須要本身寫代碼來實現交集、並集等方法

  • 無元組(tuple),必須本身寫架構或使用切片(slice)(數組)

  • 沒有相似 getattr_() 的方法,所以須要不斷檢查存在性,而不能像在 Python 中那樣設置缺省值:value = dict.get(「a_key」, 「default_value」)

  • 必須不斷檢查錯誤(至少須要顯式忽略它們)

  • 不能包含未使用的變量或包,所以有時候若是要測試一些簡單問題,須要給代碼添加註釋

  • 在 []byte 和 string 之間切換。正則表達 (regexp) 使用 []byte (可變)。這說得通,可是在一些變量之間來回切換仍是很煩人

  • Python 更爲寬鬆。你能夠用超出範圍的索引來索取字符串片斷,也不會有什麼問題,還能夠提取負值片斷,可是 Go 就不行

  • 不能使用混合類型的數據結構。也許不合規定,可是有時候在 Python 可使用混合字符串和列表的字典。在 Go 就不行,要麼清理乾淨數據結構,要麼自定義結構。感謝 Ralph Corderoy 向筆者展現瞭如何正確操做(用這個界面,盧克)
    http://play.golang.org/p/SUgl7wd9tk

  • 不能把元組或列表分解成分開的變量(如 x,y,x = [1,2,3])

  • 駝峯字規則(UpperCamelCase)(若是一個包中的函數或結構首字母未大寫,就不會暴露給其餘包)。筆者更喜歡 Python 的小寫加下劃線格式(lower_case_with_underscores)

  • 須要顯式檢查錯誤是否爲 != nil,不像 Python 有不少類型能夠用於布爾型檢查(0,「」,None 都會被解讀爲「假」)

  • 某些模塊(如 crypto/md5)的文檔不足,可是 IRC 上面的 go-nuts 很是棒,擁有特別好的支持

  • 從數字到字符串的類型轉換(int64 -> 字符串)跟[]byte -> 字符串(只用字符串([]byte))不一樣,須要用到 strconv

  • Go 的代碼讀起來更像是編程語言,而 Python寫出來更像僞代碼。Go 包含更多非數字字母字符,用 || 和 && 來表示「或」與「和」

  • 寫文件會有 File.Write([]byte) 和File.WriteString(string),這會讓習慣了 Python
    只有一種作事方法的開發者們有些不適應

  • 字符串插入很麻煩,不得不常用 fmt.Sprintf

  • 沒有構造函數,常見的作法是建立 NewType() 函數,來返回你須要的結構

  • Else 或 else if 必須格式正確,else 得跟 if 從句的大括號在一行。這很奇怪。

  • 根據函數內外位置,使用不一樣的賦值操做符,例如 = 和 :=

  • 若是隻想要相似dict.keys() 或dict.values()獲得的鍵值或取值列表,或者經過

  • dict.items()獲得的元祖列表,在 Go 裏面是沒法實現的,只能自行迭代 map,而後建立本身的列表

  • 筆者習慣創建一個取值爲函數的字典,並經過鍵值調用函數。你能夠在 Go
    裏面這麼作,可是全部的函數都得接受和返回一樣的東西,也就是說,必須具有一樣的方法簽名

  • 若是你是用 JSON, 並且是混合類型的 JSON,那麼你仍是自求多福吧。你得建立一個可以匹配你的 JSON 二進制大對象(blob)格式的個性化結構,而後解組(Unmarshall)原始 JSON 成爲你的個性化架構的一個用例。比起在 Python 中的一句「obj = json.loads(json_blob)」要費更多功夫

這麼折騰值得嗎?

值,一百萬個值,超值。速度的提高不容忽視。並且筆者認爲這也是促使 Go 成爲流行語言的重要緣由。所以在招聘時,筆者認爲把 Go 當成 Python 開發者的必備技能也很重要。

原文地址 https://blog.repustate.com/migrating-code-from-python-to-golang-what-you-need-to-know/
本文轉自 OneAPM 官方博客

相關文章
相關標籤/搜索