這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
說到concurrent,一般會想到Erlang和Go語言,這兩種語言的主打特性都是concurrent,Erlang有著20多年的曆史,是為簡化開發電信大並發和高可靠性應用而發明的語言,Go是Google從2007年開始設計,2009年opensource出來的,Go屬於一種system language,opensource的就算這兩種語言吧,公司內私人的語言則有TNSDL,SDL的一個變種,以前寫過一篇SDL和Erlang比較的文章(http://bookjovi.iteye.com/blog/1233299),這三種concurrent語言各有不同,下面看看:
1)語言設計
Erlang的實現基於虛擬機器beam,Go是編譯型語言,有著獨成一體的compiler(不同於gcc,Go很好的解決了依賴的問題,所以編譯go程式時不需向編譯c程式那樣指定include和library),TNSDL和GO類似,屬於native執行。Erlang和TNSDL主要是為電信級應用服務的,而Go的concurrent則更具有通用性,這點主要體現在concurrent的設計,Erlang和SDL是基於process之間傳遞message,而Go是goroutine組成,再加上channel,Go通過把process和message解耦使得Go的設計更有通用性和靈活性,應用可以根據自己的需求決定是否需要channel的處理。routine加channel的設計在stackless python也有(有些人說Go = C + stackless Python),正是channel的靈活性使Go中不需要Erlang中的PID,Go中的go無傳回值,Erlang中的spawn則返回PID。
Erlang沒有對message buf進行控制,使用Go的channel則可控制channel的capacity,make(chan int, 100)
2)Library支援
Erlang有著20多年的曆史,OTP中各種behavior,driver支援使得使用Erlang得心應手。Go的曆史短得多,library仍有欠缺。
3)scheduler調度器
從實現的角度看Erlang中每個process都有自己的heap,所以無法共用記憶體,總體來說Erlang的scheduler與Linux kernel非常相似;Go和SDL屬於native執行,這裡主要討論公平性的問題,Erlang中每個process有reduction,類似於Linux kernel中process的time slice,Go是native執行,那麼Go的runtime是如何控制每個goroutine的公平性呢?答案是沒有,native執行的goroutine無法像Erlang那樣保證公平性,goroutine只能在syscall、io、channel read write操作時才能有機會重新執行schedule函數,以執行其餘的goroutine。在concurrent語言中,如不能很好的解決公平調度和優先順序調度是個很大的問題。
鑒於Go現在還不是太成熟,或許以後會有改進,scheduler和GC都有很多的討論,現在scheduler的實現邏輯及其簡單(G & M),與Erlang 調度器相比更是簡單(裡面有些bug,還有公平性的問題)。
Erlang scheduler位於:otp/erts/emulator/beam/erl_process.c
Go scheduler位於:go/src/pkg/runtime/proc.c
4)memory model 記憶體模型
Erlang中每個process有自己的heap,stack在heap的底部,這裡的stack是Erlang process的stack,類似於Java中的運算元棧,stack向下增長,stack top如遇到heap top,則進行GC,GC後stack移到新的地方。
Go是native執行,goroutine的stack是segment stack,TNSDL的runtime也是使用這種segment stack,segment stack就是一個程式中有很多stack執行,stack的切換則通過setjmp,longjmp實現的。(setjmp和longjmp的一個主要應用就是concurrent,另一個是在C中類比try catch)
5)GC記憶體回收
Erlang的GC屬於分代演算法,有個old heap,有minor gc和full sweep,總體來說和Java類似,只不過Erlang沒有mark的過程,直接根據rootset找到所有Eterm放在新分配的heap的。
Go現在是mark-sweep,以後會使用IBM的低延時GC演算法。
6)高可靠性
Erlang中有個builtin的高可靠性,如link和monitor機制。
Go是一個通用性的設計,雖沒有built-in的link和monitor,goroutine則可使用defer來實現link的效果。
7)效能
Go的實際目標之一就是高效能,這也是為什麼go是一種編譯型語言。理論上分析goroutine的效能會好於Erlang的process,但軟體設計原則中效能只是衡量標準之一而不是全部。
好了,話太多,就說到這裡了,個人還是很喜歡Go的設計,未來程式語言的實際應該像go和Erlang那樣扔掉mulitthreading的設計(Java,Python),同時channel的使用使得go的實際更具通用性和靈活性,這是concurrent語言被行業接受非常關鍵性的因素。