簡單來說:協程十分輕量,可以在一個進程中執行有數以十萬計的協程,依舊保持高性能。
進程、線程、協程的關系和區別:
- 進程擁有自己獨立的堆和棧,既不共享堆,亦不共享棧,進程由操作系統調度。
- 線程擁有自己獨立的棧和共享的堆,共享堆,不共享棧,線程亦由操作系統調度(標准線程是的)。
- 協程和線程一樣共享堆,不共享棧,協程由程序員在協程的代碼里顯示調度。
堆和棧的區別請參看: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.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/