1. 程式人生 > >程序、執行緒、輕量級程序、協程和go中的Goroutine 那些事兒

程序、執行緒、輕量級程序、協程和go中的Goroutine 那些事兒

一、程序

作業系統中最核心的概念是程序,分散式系統中最重要的問題是程序間通訊。

程序是“程式執行的一個例項” ,擔當分配系統資源的實體。程序建立必須分配一個完整的獨立地址空間。

程序切換只發生在核心態,兩步:1 切換頁全域性目錄以安裝一個新的地址空間 2 切換核心態堆疊和硬體上下文。  另一種說法類似:1 儲存CPU環境(暫存器值、程式計數器、堆疊指標)2修改記憶體管理單元MMU的暫存器 3 轉換後備緩衝器TLB中的地址轉換快取內容標記為無效。

二、執行緒

書中的定義:執行緒是程序的一個執行流,獨立執行它自己的程式程式碼

維基百科:執行緒英語thread)是作業系統能夠進行運算

排程的最小單位。

執行緒上下文一般只包含CPU上下文及其他的執行緒管理資訊。執行緒建立的開銷主要取決於為執行緒堆疊的建立而分配記憶體的開銷,這些開銷並不大。執行緒上下文切換髮生在兩個執行緒需要同步的時候,比如進入共享資料段。切換隻CPU暫存器值需要儲存,並隨後用將要切換到的執行緒的原先儲存的值重新載入到CPU暫存器中去。

使用者級執行緒主要缺點在於對引起阻塞的系統呼叫的呼叫會立即阻塞該執行緒所屬的整個程序。核心實現執行緒則會導致執行緒上下文切換的開銷跟程序一樣大,所以折衷的方法是輕量級程序(Lightweight)。在Linux中,一個執行緒組基本上就是實現了多執行緒應用的一組輕量級程序。我理解為 程序中存在使用者執行緒、輕量級程序、核心執行緒。

語言層面實現輕量級程序的比較少,stackless Python,erlang支援,Java並不支援。

三、協程

協程的定義?顏開、許式偉均只說協程是輕量級的執行緒,一個程序可輕鬆建立數十萬計的協程。仔細研究下,個人感覺這些都是忽悠人的說法。從維基百科上看,從Knuth老爺子的基本演算法捲上看“子程式其實是協程的特例”。子程式是什麼?子程式英語Subroutineprocedurefunctionroutinemethodsubprogram),就是函式嘛!所以協程也沒什麼了不起的,就是種更一般意義的程式元件,那你記憶體空間夠大,建立多少個函式還不是隨你麼?

協程可以通過yield來呼叫其它協程。通過yield方式轉移執行權的協程之間不是呼叫者與被呼叫者的關係,而是彼此對稱、平等的。協程的起始處是第一個入口點,在協程裡,返回點之後是接下來的入口點。子例程的生命期遵循後進先出(最後一個被呼叫的子例程最先返回);相反,協程的生命期完全由他們的使用的需要決定。

執行緒和協程的區別:

一旦建立完執行緒,你就無法決定他什麼時候獲得時間片,什麼時候讓出時間片了,你把它交給了核心。而協程編寫者可以有一是可控的切換時機,二是很小的切換代價。從作業系統有沒有排程權上看,協程就是因為不需要進行核心態的切換,所以會使用它,會有這麼個東西。賴永浩和dccmx 這個定義我覺得相對準確  協程-使用者態的輕量級的執行緒。(http://blog.dccmx.com/2011/04/coroutine-concept/)

為什麼要用協程:

協程有助於實現:

  • 狀態機:在一個子例程裡實現狀態機,這裡狀態由該過程當前的出口/入口點確定;這可以產生可讀性更高的程式碼。
  • 角色模型:並行的角色模型,例如計算機遊戲。每個角色有自己的過程(這又在邏輯上分離了程式碼),但他們自願地向順序執行各角色過程的中央排程器交出控制(這是合作式多工的一種形式)。
  • 產生器:它有助於輸入/輸出和對資料結構的通用遍歷。
顏開總結的支援協程的常見的語言和平臺,可做參考,但應深入調研下才好。 Go語言併發之美

四、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/