最近,看一些文章,提到「協程」的概念,心想,進程,線程,協程,前兩個很容易,任何一本關於操做系統的書都有說,開發時也常常用,可是協程呢?以前也遇到這個詞,可是今天,查了一下資料。下面是一我的的總結。php
遷移到:http://www.bdata-cap.com/newsinfo/1713872.html
電話面試被問到go的協程……雖然用 python 時候在 Eurasia 和 eventlet 裏瞭解過協程,但本身對協程的概念也就是輕量級線程,還有一個很通俗的紅綠燈說法:線程要守規則,協程看到紅燈可是沒有車仍能夠通行。如今總結各個資料,從我的理解上說明下進程、線程、輕量級進程、協程,以及 go 中的 goroutine 那些事兒。html
操做系統中最核心的概念是進程,分佈式系統中最重要的問題是進程間通訊。java
進程是「程序執行的一個實例」,擔當分配系統資源的實體。進程建立必須分配一個完整的獨立地址空間。python
進程切換隻發生在內核態,兩步:golang
另外一種說法相似:面試
線程是進程的一個執行流,獨立執行它本身的程序代碼。線程(thread)是操做系統可以進行運算調度的最小單位。算法
線程上下文通常只包含CPU上下文及其餘的線程管理信息。線程建立的開銷主要取決於爲線程堆棧的創建而分配內存的開銷,這些開銷並不大。線程上下文切換髮生在兩個線程須要同步的時候,好比進入共享數據段。切換隻CPU寄存器值須要存儲,並隨後用將要切換到的線程的原先存儲的值從新加載到CPU寄存器中去。編程
用戶級線程主要缺點在於對引發阻塞的系統調用的調用會當即阻塞該線程所屬的整個進程。內核實現線程則會致使線程上下文切換的開銷跟進程同樣大,因此折衷的方法是輕量級進程(Lightweight)。在 Linux 中,一個線程組基本上就是實現了多線程應用的一組輕量級進程。進程中存在用戶線程、輕量級進程、內核線程。緩存
語言層面實現輕量級進程的比較少,stackless python,erlang 支持,java 並不支持。網絡
協程是輕量級的線程,一個進程可輕鬆建立數十萬計的協程。從維基百科上看,從Knuth老爺子的基本算法捲上看「子程序實際上是協程的特例」。子程序是什麼?子程序(Subroutine, procedure, function, routine, method, subprogram),就是函數嘛!因此協程也沒什麼了不得的,就是更通常意義的程序組件,那你內存空間夠大,建立多少個函數還不是隨你嗎?
協程能夠經過yield來調用其它協程。經過yield方式轉移執行權的協程之間不是調用者與被調用者的關係,而是彼此對稱、平等的。協程的起始處是第一個入口點,在協程裏,返回點以後是接下來的入口點。子例程的生命期遵循後進先出(最後一個被調用的子例程最早返回);相反,協程的生命期徹底由他們的使用的須要決定。
一旦建立完線程,你就沒法決定他何時得到時間片,何時讓出時間片了,你把它交給了內核。而協程編寫者,一是可控的切換時機,二是很小的切換代價。從操做系統有沒有調度權上看,協程就是由於不須要進行內核態的切換,因此會使用它,會有這麼個東西。賴永浩和dccmx 這個定義我以爲相對準確 協程-用戶態的輕量級的線程。(http://blog.dccmx.com/2011/04/coroutine-concept/)
協程有助於實現:
語言/平臺 |
實現版本 |
協程名稱 |
備註 |
GoLang |
原生支持 |
goroutine |
|
Erlang |
原生支持 |
process |
函數式編程 |
Scala |
原生支持 |
actor |
函數式編程 |
Python |
2.5 版本後 |
coroutine |
官方 Python 不徹底實現,Stackless Python 支持 |
Perl |
6.0 版本後 |
coroutine |
|
Ruby |
1.9 版本後 |
fiber |
|
Lua |
原生支持 |
coroutine |
|
C# |
.Net 2.0 版本後 |
fiber |
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)