不是語言之爭---Go vs Erlang

由於 雲巴 系統對高併發、低延遲的需求,咱們對各個語言、平臺作了不少的調研比較工做。這天然就包括致力於開發高併發應用的 Go 和 Erlang。正則表達式

併發

Go 對高併發的支持經過 goroutine 實現。goroutine 能夠理解爲輕量級的 線程(thread)。同一個 Go 應用建立的 goroutine 共享地址空間。shell

Erlang 的高併發經過輕量級 進程(process)實現,每個進程都有獨立的狀態記錄。後端

另外,使用 goroutine 要注意,goroutine 運行完畢後,佔用的內存放回內存池備用,不會釋放。服務器

對於每個任務都須要有獨立狀態的場景,Erlang 的 process 更有優點。併發

搶佔式調度

Erlang 的任務調度器有一個 reduction budget 的概念。進程的任何操做都會形成預算消耗,包括 函數調用、調用 BIF、進程堆垃圾回收、ETS 讀寫、發消息(目標郵箱堆積的消息越多,消耗越大)。Erlang 的 正則表達式庫 也被作了修改以支持 reductions。因此若是進程在長時間執行正則表達式匹配,也同樣會消耗 reductions,也會被搶佔。app

Go 以前的調度器只在 syscall 發生時調度,優化後能夠在任何函數調用時調度。可是要注意,若是在 goroutine 裏寫一個死循環,Go 的調度器不能有效搶佔,同一個調度器的 其餘 goroutine 會被掛起。框架

垃圾回收

像 Java 同樣,Go 的垃圾回收是全局的,這意味着一旦垃圾回收被觸發,全部的 goroutine 都會被暫停,形成一段時間的業務延遲。函數

Erlang 的垃圾回收是 進程 級別的,每個進程都有本身獨立的垃圾回收器,一個進程的垃圾回收被觸發,不會形成其餘進程被掛起。相對來講帶來的業務延遲小。高併發

錯誤處理

Erlang 的每個進程都有 進程 ID (PID),同時也能夠給進程註冊名字,也就是說每個進程都有獨立的身份,能夠有效的監控每個進程的狀態。進程異常退出時,能夠捕捉到退出事件,並重啓進程(參見 otp 的 supervisor/worker)。單元測試

Go 的 goroutine 沒有身份識別,goroutine 的狀態沒辦法監控。

動態反射

Erlang 動態語言的特色,使它自然支持 REPL,另外 Erlang 支持 remote shell,咱們能夠在 Erlang 運行時,鏈接到 remote shell 與任何一個進程交互。這些特性對一個須要長期運行的複雜系統的維護帶來了極大的便利。開發階段也能有一些便利。

Go 是靜態語言,不支持 REPL。

靜態編譯

Erlang 是動態語言,有全部動態語言的全部缺點:

  1. 運行速度慢
  2. 不能作早期錯誤檢查,須要依賴全覆蓋單元測試
  3. 代碼規模大了,給編寫帶來困擾

Erlang 如今也引入了 spec,對函數的參數返回值在編譯時作類型檢查,可是跟靜態語言比起來效果差的很遠。

不過正是由於是動態語言,Erlang 實現了運行時代碼替換,這個特性對一個須要長時間運行的工業級產品,是一個很是重要的功能。

Go 是靜態語言,運行速度快,編譯時作嚴格的類型檢查,能夠避免不少隱患。

框架

Erlang 的 OTP 框架支持服務器端開發常見的幾種模式(applications, supervisors, wokers),方便代碼的組織。

Go 暫時沒看到相似的框架。

第三方庫支持

Go 是一個相對比較新的語言,雖然說如今不少項目都開始支持 Go,但不少第三方庫的成熟度暫時不如 Erlang。

總結

對於要求低延遲、高併發的後端服務,咱們近期仍是採用 Erlang 爲主。但使用 Erlang 的過程當中,Erlang 缺少靜態檢查的手段,也是一個很麻煩的問題,目前的作法是要求你們都使用 IntelliJ IDEA 編寫代碼,能夠經過 IDE 提早發現部分語言問題。

同時咱們會持續關注 Go 的發展。

關於做者:
weibo: @Tiger_張虎, 雲巴 (yunba.io) 創始人,yunba.io 雲後端服務。 JPush 創始人,原CTO。 Oracle VM 創始團隊成員。
原文:http://zhang.hu/go-vs-erlang/

相關文章
相關標籤/搜索