這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
簡單來說:協程十分輕量,可以在一個進程中執行有數以十萬計的協程,依舊保持高效能。
進程、線程、協程的關係和區別:
進程擁有自己獨立的堆和棧,既不共用堆,亦不共用棧,進程由作業系統調度。
線程擁有自己獨立的棧和共用的堆,共用堆,不共用棧,線程亦由作業系統調度(標準線程是的)。
協程和線程一樣共用堆,不共用棧,協程由程式員在協程的代碼裡顯示調度。
堆和棧的區別請參看:http://www.cnblogs.com/ghj1976/p/3623037.html
協程和線程的區別是:協程避免了無意義的調度,由此可以提高效能,但也因此,程式員必須自己承擔調度的責任。
執行協程只需要極少的棧記憶體(大概是4~5KB),預設情況下,線程棧的大小為1MB。
goroutine就是一段代碼,一個函數入口,以及在堆上為其分配的一個堆棧。所以它非常廉價,我們可以很輕鬆的建立上萬個goroutine,但它們並不是被作業系統所調度執行。
和所有其他並發架構裡的協程一樣,goroutine裡所謂“無鎖”的優點只在單線程下有效,如果$GOMAXPROCS > 1並且協程間需要通訊,Go運行庫會負責加鎖保護資料,這也是為什麼sieve.go這樣的例子在多CPU多線程時反而更慢的原因.
http://my.oschina.net/Obahua/blog/144549
goroutine 的一個主要特性就是它們的消耗;建立它們的初始記憶體成本很低廉(與需要 1 至 8MB 記憶體的傳統 POSIX 線程形成鮮明對比)以及根據需要動態增長和縮減佔用的資源。這使得 goroutine 會從 4096 位元組的初始棧記憶體佔用開始按需增長或縮減記憶體佔用,而無需擔心資源的耗盡。
為了實現這個目標,連結器(5l、6l 和 8l)會在每個函數前插入一個序文,這個序文會在函數被調用之前檢查判斷當前的資源是否滿足調用該函數的需求(備忘 1)。如果不滿足,則調用 runtime.morestack 來分配新的棧頁面(備忘 2),從函數的調用者那裡拷貝函數的參數,然後將控制權返回給調用者。此時,已經可以安全地調用該函數了。當函數執行完畢,事情並沒有就此結束,函數的返回參數又被拷貝至調用者的棧結構中,然後釋放無用的棧空間。
通過這個過程,有效地實現了棧記憶體的無限使用。假設你並不是不斷地在兩個棧之間往返,通俗地講叫棧分割,則代價是十分低廉的。
參考資料:
【翻譯】為什麼 goroutine 的棧記憶體無窮大?
http://my.oschina.net/Obahua/blog/144549
進程、線程和協程的理解
http://blog.leiqin.name/2012/12/02/%E8%BF%9B%E7%A8%8B%E3%80%81%E7%BA%BF%E7%A8%8B%E5%92%8C%E5%8D%8F%E7%A8%8B%E7%9A%84%E7%90%86%E8%A7%A3.html
協程架構的堆棧大小陷阱
http://blog.csdn.net/huyiyang2010/article/details/6104891
Coroutine及其實現
http://www.cnblogs.com/foxmailed/archive/2014/01/08.html
goroutine背後的系統知識
http://www.sizeofvoid.net/goroutine-under-the-hood/