原文:http://www.cnblogs.com/shenguanpu/archive/2013/05/05/3060616.htmlphp
電話面試被問到go的協程,曾經的軍偉也問到過我協程。雖然用python時候在Eurasia和eventlet裏瞭解過協程,但本身對協程的概念也就是輕量級線程,還有一個很通俗的紅綠燈說法:線程要守規則,協程看到紅燈可是沒有車仍能夠通行。如今總結各個資料,從我的理解上說明下 進程 線程 輕量級進程 協程 go中的goroutine 那些事兒。html
1、進程java
操做系統中最核心的概念是進程,分佈式系統中最重要的問題是進程間通訊。python
進程是「程序執行的一個實例」 ,擔當分配系統資源的實體。進程建立必須分配一個完整的獨立地址空間。linux
進程切換只發生在內核態,兩步:1 切換頁全局目錄以安裝一個新的地址空間 2 切換內核態堆棧和硬件上下文。 另外一種說法相似:1 保存CPU環境(寄存器值、程序計數器、堆棧指針)2修改內存管理單元MMU的寄存器 3 轉換後備緩衝器TLB中的地址轉換緩存內容標記爲無效。golang
2、線程面試
書中的定義:線程是進程的一個執行流,獨立執行它本身的程序代碼。算法
維基百科:線程(英語:thread)是操做系統可以進行運算調度的最小單位。編程
線程上下文通常只包含CPU上下文及其餘的線程管理信息。線程建立的開銷主要取決於爲線程堆棧的創建而分配內存的開銷,這些開銷並不大。線程上下文切換髮生在兩個線程須要同步的時候,好比進入共享數據段。切換隻CPU寄存器值須要存儲,並隨後用將要切換到的線程的原先存儲的值從新加載到CPU寄存器中去。緩存
用戶級線程主要缺點在於對引發阻塞的系統調用的調用會當即阻塞該線程所屬的整個進程。內核實現線程則會致使線程上下文切換的開銷跟進程同樣大,因此折衷的方法是輕量級進程(Lightweight)。在linux中,一個線程組基本上就是實現了多線程應用的一組輕量級進程。我理解爲 進程中存在用戶線程、輕量級進程、內核線程。
語言層面實現輕量級進程的比較少,stackless python,erlang支持,java並不支持。
3、協程
協程的定義?顏開、許式偉均只說協程是輕量級的線程,一個進程可輕鬆建立數十萬計的協程。仔細研究下,我的感受這些都是忽悠人的說法。從維基百科上看,從Knuth老爺子的基本算法捲上看「子程序實際上是協程的特例」。子程序是什麼?子程序(英語:Subroutine, procedure, function, routine, method, subprogram),就是函數嘛!因此協程也沒什麼了不得的,就是種更通常意義的程序組件,那你內存空間夠大,建立多少個函數還不是隨你麼?
協程能夠經過yield來調用其它協程。經過yield方式轉移執行權的協程之間不是調用者與被調用者的關係,而是彼此對稱、平等的。協程的起始處是第一個入口點,在協程裏,返回點以後是接下來的入口點。子例程的生命期遵循後進先出(最後一個被調用的子例程最早返回);相反,協程的生命期徹底由他們的使用的須要決定。
線程和協程的區別:
一旦建立完線程,你就沒法決定他何時得到時間片,何時讓出時間片了,你把它交給了內核。而協程編寫者能夠有一是可控的切換時機,二是很小的切換代價。從操做系統有沒有調度權上看,協程就是由於不須要進行內核態的切換,因此會使用它,會有這麼個東西。賴永浩和dccmx 這個定義我以爲相對準確 協程-用戶態的輕量級的線程。(http://blog.dccmx.com/2011/04/coroutine-concept/)
爲何要用協程:
協程有助於實現:
4、go中的Goroutine
go中的Goroutine, 廣泛認爲是協程的go語言實現。《Go語言編程》中說goroutine是輕量級線程(即協程coroutine, 原書90頁). 在第九章進階話題中, 做者又一次提到, "從根本上來講, goroutine就是一種go語言版本的協程(coroutine)" (原書204頁). 但做者Rob Pike並不這麼說。
「一個Goroutine是一個與其餘goroutines 併發運行在同一地址空間的Go函數或方法。一個運行的程序由一個或更多個goroutine組成。它與線程、協程、進程等不一樣。它是一個goroutine。」
在棧實現上,它的編譯器分支下的實現gccgo是線程pthread,6g上是多路複用的threads(6g/8g/5g分別表明64位、32位及Arm架構編譯器)
infoQ一篇文章介紹特性也說道: goroutine是Go語言運行庫的功能,不是操做系統提供的功能,goroutine不是用線程實現的。具體可參見Go語言源碼裏的pkg/runtime/proc.c
老趙認爲goroutine就是把類庫功能放進了語言裏。
goroutine的併發問題:goroutine在共享內存中運行,通訊網絡可能死鎖,多線程問題的調試糟糕透頂等等。一個比較好的建議規則:不要經過共享內存通訊,相反,經過通訊共享內存。
並行 併發區別:
並行是指程序的運行狀態,要有兩個線程正在執行才能算是Parallelism;併發指程序的邏輯結構,Concurrency則只要有兩個以上線程還在執行過程當中便可。簡單地說,Parallelism要在多核或者多處理器狀況下才能作到,而Concurrency則不須要。(http://stackoverflow.com/questions/1050222/concurrency-vs-parallelism-what-is-the-difference)
參考資料:
《現代操做系統》《分佈式系統原理與範型》《深刻理解linux內核》《go程序設計語言》
賴勇浩 協程三篇之僅一篇 http://blog.csdn.net/lanphaday/article/details/5397038
顏開 http://qing.blog.sina.com.cn/tj/88ca09aa33002ele.html
go程序設計語言中文 http://tonybai.com/2012/08/28/the-go-programming-language-tutorial-part3/ (中文翻譯定義中漏了個 併發)
go程序設計語言英文http://go.googlecode.com/hg-history/release-branch.r60/doc/GoCourseDay3.pdf
go語言初體驗 http://blog.dccmx.com/2011/01/go-taste/
https://zh.wikipedia.org/wiki/Go
https://zh.wikipedia.org/wiki/進程
https://zh.wikipedia.org/wiki/線程
http://stackoverflow.com/questions/1050222/concurrency-vs-parallelism-what-is-the-difference
http://www.infoq.com/cn/articles/knowledge-behind-goroutine
go語言編程書評:http://book.douban.com/review/5726587/
http://blog.zhaojie.me/2013/04/why-channel-and-goroutine-in-golang-are-buildin-libraries-for-other-platforms.html