摘要:轉用一門新語言一般是一項大決策,尤爲是當你的團隊成員中只有一個使用過它時。今年 Stream 團隊的主要編程語言從 Python 轉向了 Go。本文解釋了其背後的九大緣由以及如何作好這一轉換。html
轉用一門新語言一般是一項大決策,尤爲是當你的團隊成員中只有一個使用過它時。今年 Stream 團隊的主要編程語言從 Python 轉向了 Go。本文解釋了其背後的九大緣由以及如何作好這一轉換。python
Go的優點git
緣由 1:性能程序員
Go 極其地快。其性能與 Java 或 C++類似。在咱們的使用中,Go 通常比 Python 要快 30 倍。如下是 Go 與 Java 之間的基準比較:github
緣由 2:語言性能很重要golang
對不少應用來講,編程語言只是簡單充當了其與數據集之間的膠水。語言自己的性能經常無關輕重。編程
可是 Stream 是一個 API 提供商,服務於世界 500 強以及超過 2 億的終端用戶。數年來咱們已經優化了 Cassandra、PostgreSQL、Redis 等等,然而最終抵達了所使用語言的極限。json
Python 很是棒,可是其在序列化/去序列化、排序和聚合中表現欠佳。咱們常常會遇到這樣的問題:Cassandra 用時 1ms 檢索了數據,Python 卻須要 10ms 將其轉化成對象。api
緣由 3:開發者效率&不要過於創新七牛雲存儲
看一下絕佳的入門教程《開始學習 Go 語言》(http://howistart.org/posts/go/1/)中的一小段代碼:
1 package main 2 type openWeatherMap struct{}func (w openWeatherMap) temperature(city string) (float64, error) { 3 resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&q=" + city) 4 if err != nil { 5 return 0, err 6 } 7 defer resp.Body.Close() 8 var d struct { 9 Main struct { 10 Kelvin float64 `json:"temp"` 11 } `json:"main"` 12 } 13 if err := json.NewDecoder(resp.Body).Decode(&d); err != nil { 14 return 0, err 15 } 16 log.Printf("openWeatherMap: %s: %.2f", city, d.Main.Kelvin) 17 return d.Main.Kelvin, nil}
若是你是一個新手,看到這段代碼你並不會感到吃驚。它展現了多種賦值、數據結構、指針、格式化以及內置的 HTTP 庫。
當我第一次編程時,我很喜歡使用 Python 的高階功能。Python 容許你創造性地使用正在編寫的代碼,好比,你能夠:
毋庸置疑這些代碼頗有趣,但也使得在讀取其餘人的工做時,代碼變得難以理解。
Go 強迫你堅持打牢基礎,這也就爲讀取任意代碼帶來了便利,並能很快搞明白當下發生的事情。
注意:固然如何容易仍是要取決於你的使用案例。若是你要建立一個基本的 CRUD API,我仍是建議你使用 Django + DRF,或者 Rails。
緣由 4:併發性&通道
Go 做爲一門語言致力於使事情簡單化。它並未引入不少新概念,而是聚焦於打造一門簡單的語言,它使用起來異常快速而且簡單。其惟一的創新之處是 goroutines 和通道。Goroutines 是 Go 面向線程的輕量級方法,而通道是 goroutines 之間通訊的優先方式。
建立 Goroutines 的成本很低,只需幾千個字節的額外內存,正因爲此,才使得同時運行數百個甚至數千個 goroutines 成爲可能。你能夠藉助通道實現 goroutines 之間的通訊。Go 運行時間能夠表示全部的複雜性。Goroutines 以及基於通道的併發性方法使其很是容易使用全部可用的 CPU 內核,並處理併發的 IO——全部不帶有複雜的開發。相較於 Python/Java,在一個 goroutine 上運行一個函數須要最小的樣板代碼。你只需使用關鍵詞「go」添加函數調用:
1 package main 2 import ( 3 "fmt" 4 "time")func say(s string) { 5 for i := 0; i < 5; i++ { 6 time.Sleep(100 * time.Millisecond) 7 fmt.Println(s) 8 }}func main() { 9 go say("world") 10 say("hello")}
Go 的併發性方法很是容易上手,相較於 Node 也頗有趣;在 Node 中,開發者必須密切關注異步代碼的處理。
併發性的另外一個優質特性是競賽檢測器,這使其很容易弄清楚異步代碼中是否存在競態條件。下面是一些上手 Go 和通道的很好的資源:
緣由 5:快速的編譯時間
當前咱們使用 Go 編寫的最大微服務的編譯時間只需 6 秒。相較於 Java 和 C++呆滯的編譯速度,Go 的快速編譯時間是一個主要的效率優點。我熱愛擊劍,可是當我依然記得代碼應該作什麼之時,事情已經完成就更好了。
Go 以前的代碼編譯
緣由 6:打造團隊的能力
首先,最明顯的一點是:Go 的開發者遠沒有 C++和 Java 等舊語言多。據知,有 38% 的開發者瞭解 Java,19.3% 的開發者瞭解 C++,只有 4.6% 的開發者知道 Go。GitHub 數據代表了類似的趨勢:相較於 Erlang、Scala 和 Elixir,Go 更爲流行,可是相較於 Java 和 C++ 就不是了。
幸運的是 Go 很是簡單,且易於學習。它只提供了基本功能而沒有多餘。Go 引入的新概念是「defer」聲明,以及內置的帶有 goroutines 和通道的併發性管理。正是因爲 Go 的簡單性,任何的 Python、Elixir、C++、Scala 或者 Java 開發者皆可在一月內組建成一個高效的 Go 團隊。
緣由 7:強大的生態系統
對咱們這麼大小的團隊(大約 20 人)而言,生態系統很重要。若是你須要重作每塊功能,那就沒法爲客戶創造收益了。Go 有着強大的工具支持,面向 Redis、RabbitMQ、PostgreSQL、Template parsing、Task scheduling、Expression parsing 和 RocksDB 的穩定的庫。
Go 的生態系統相比於 Rust、Elixir 這樣的語言有很大的優點。固然,它又略遜於 Java、Python 或 Node 這樣的語言,但它很穩定,並且你會發如今不少基礎需求上,已經有高質量的文件包可用了。
緣由 8:GOFMT,強制代碼格式
Gofmt 是一種強大的命令行功能,內建在 Go 的編譯器中來規定代碼的格式。從功能上看,它相似於 Python 的 autopep8。格式一致很重要,但實際的格式標準並不老是很是重要。Gofmt 用一種官方的形式規格代碼,避免了沒必要要的討論。
緣由 9:gRPC 和 Protocol Buffers
Go 語言對 protocol buffers 和 gRPC 有一流的支持。這兩個工具能一塊兒友好地工做以構建須要經過 RPC 進行通訊的微服務器(microservices)。咱們只須要寫一個清單(manifest)就能定義 RPC 調用發生的狀況和參數,而後從該清單將自動生成服務器和客戶端代碼。這樣產生代碼不只快速,同時網絡佔用也很是少。
從相同的清單,咱們能夠從不一樣的語言生成客戶端代碼,例如 C++、Java、Python 和 Ruby。所以內部通訊的 RESET 端點不會產生分歧,咱們每次也就須要編寫幾乎相同的客戶端和服務器代碼。
使用 Go 語言的缺點
缺點 1:缺乏框架
Go 語言沒有一個主要的框架,如 Ruby 的 Rails 框架、Python 的 Django 框架或 PHP 的 Laravel。這是 Go 語言社區激烈討論的問題,由於許多人認爲咱們不該該從使用框架開始。在不少案例狀況中確實如此,但若是隻是但願構建一個簡單的 CRUD API,那麼使用 Django/DJRF、Rails Laravel 或 Phoenix 將簡單地多。
缺點 2:錯誤處理
Go 語言經過函數和預期的調用代碼簡單地返回錯誤(或返回調用堆棧)而幫助開發者處理編譯報錯。雖然這種方法是有效的,但很容易丟失錯誤發生的範圍,所以咱們也很難向用戶提供有意義的錯誤信息。錯誤包(errors package)能夠容許咱們添加返回錯誤的上下文和堆棧追蹤而解決該問題。
另外一個問題是咱們可能會忘記處理報錯。諸如 errcheck 和 megacheck 等靜態分析工具能夠避免出現這些失誤。雖然這些解決方案十分有效,但可能並非那麼正確的方法。
缺點 3:軟件包管理
Go 語言的軟件包管理絕對不是完美的。默認狀況下,它沒有辦法制定特定版本的依賴庫,也沒法建立可複寫的 builds。相比之下 Python、Node 和 Ruby 都有更好的軟件包管理系統。然而經過正確的工具,Go 語言的軟件包管理也能夠表現得不錯。
咱們可使用 Dep 來管理依賴項,它也能指定特定的軟件包版本。除此以外,咱們還可使用一個名爲 VirtualGo 的開源工具,它能輕鬆地管理 Go 語言編寫的多個項目。
Python vs Go
咱們實施的一個有趣實驗是用 Python 寫排名 feed,而後用 Go 改寫。看下面這種排序方法的示例:
1 { 2 "functions": { 3 "simple_gauss": { 4 "base": "decay_gauss", 5 "scale": "5d", 6 "offset": "1d", 7 "decay": "0.3" 8 }, 9 "popularity_gauss": { 10 "base": "decay_gauss", 11 "scale": "100", 12 "offset": "5", 13 "decay": "0.5" 14 } 15 }, 16 "defaults": { 17 "popularity": 1 18 }, 19 "score": "simple_gauss(time)*popularity"}
Python 和 Go 代碼都須要如下要求從而支持上面的排序方法:
開發 Python 版本排序代碼大約須要 3 天,包括寫代碼、測試和創建文檔。接下來,我麼花費大約 2 周的時間優化代碼。其中一個優化是把得分表達 simple_gauss(time)*popularity 轉譯進一個抽象語法樹。咱們也實現了 caching logic,以後會預先計算每次的得分。
相比之下,開發 Go 版本的代碼須要 4 天,但以後不須要更多的優化。因此雖然最初的開發上 Python 更快,但 Go 最終須要的工做量更少。此外,Go 代碼要比高度優化的 python 代碼快了 40 多倍。
以上只是咱們轉向 Go 所體驗到的一種好處。固然,也不能這麼作比較:
Elixir vs Go
咱們評估的另外一種語言是 Elixir。Elixir 創建在 Erlang 虛擬機上。這是一種迷人的語言,咱們之因此想到它是由於咱們組員中有一個在 Erlang 上很是有經驗。
在使用案例中,咱們觀察到 Go 的原始性能更好。Go 和 Elixir 都能很好地處理數千條並行需求,然而,若是是單獨的要求,Go 實際上更快。相對於 Elixir,咱們選擇 Go 的另外一個緣由是生態系統。在咱們需求的組件上,Go 的庫更爲成熟。在不少案例中,Elixir 庫不適合產品使用。同時,也很難找到/訓練一樣使用 Elixir 的開發者。
結論
Go 是一種很是高效的語言,高度支持併發性。同時,它也像 C++和 Java 同樣快。雖然相比於 Python 和 Ruby,使用 Go 創建東西須要更多的時間,但在後續的代碼優化上能夠節省大量時間。在 Stream,咱們有個小型開發團隊爲 2 億終端用戶提供 feed 流。對新手開發者而言,Go 結合了強大的生態系統、易於上手,也有超快的表現、高度支持併發性,富有成效的編程環境使它成爲了一種好的選擇。Stream 仍舊使用 Python 作個性化 feed,但全部性能密集型的代碼將會用 Go 來編寫。
對每位程序員來講,無論哪一種語言,「學的紮實,能學以至用」纔是王道!本文就爲對 Go 語言感興趣的朋友們提供一些口碑不錯的學習書籍建議。
1、《Go語言學習筆記》
(未找到對應版本的電子書,你們能夠去做者github:https://github.com/qyuhen/book)
推薦理由:做爲時下流行的一種系統編程語言,Go 簡單易學,性能很好,且支持各種主流平臺。已有大量項目採用 Go 編寫,這其中就包括 Docker 等明星做品,其開發和執行效率早已被證實。本書經四年多逐步完善,內容覆蓋了語言、運行時、性能優化、工具鏈等各層面知識。且內容經大量讀者反饋和校對,沒有明顯的缺陷和錯誤。
適合人羣:本書不適合編程初學入門,可供有實際編程經驗或正在使用Go 工做的人羣參考。
2、《Go語言實戰》
推薦理由:William Kennedy是一位熟練的軟件開發者,也是博客GoingGo.Net的做者。本書向讀者提供一個專一、全面且符合語言習慣的視角。Go語言實戰同時關注語言的規範和實現,涉及的內容包括語法、類型系統、併發、管道、測試,以及其餘一些主題。
適合人羣:全覆蓋,側重初學者
3、《Go語言編程》
推薦理由:做者是業界大神級別的人物,七牛雲存儲團隊的核心技術人員,也是國內最先應用和推廣 Go 語言技術的專家!本書內容簡煉,重點突出,將 Go 語言的特性作了充分的分析和總結,並給出 Go 實例的代碼;內容體系可能更適合有必定編程基礎的程序員閱讀!本書是國內最先的中文版的 Go 技術書籍之一,雖然發行時間比較早,但仍能夠做爲重要參考!電子版和紙質版都有!
適合人羣:全覆蓋,側重有經驗的程序員
4、《Go 語言程序設計》
推薦理由:國外最經典的Go語言著做,Go語言編程的先驅者Mark Summerfield的實踐經驗總結。這是一本Go語言實戰指南,幫你瞭解Go語言,按Go語言的方式思考,以及使用Go語言來編寫高性能軟件。
做者展現瞭如何編寫充分利用Go語言突破性的特性和慣用法的代碼,以及Go語言在其餘語言之上所作的改進,並着重強調了Go語言的關鍵創新。
注重實踐教學,每章都提供了多個通過精心設計的代碼示例。
由國內第一個核心服務徹底採用Go語言實現的團隊——七牛團隊核心成員翻譯。
適合人羣:適用於有必定Go語言編程編程的愛好者,很是適合做爲Go語言編程進階教程。