Goroutine 和 Channel 講解
文章目錄
前言
Go 語言中並發程序可以用兩種方式來實現。
一種是 goroutine
和 channel
,其支持 “交談循序程式”(communicating sequential processes)或被簡稱為 CSP。
CSP 是一個現代的並發程式模型,在這種程式模型中值會在不同的運行實例(goroutine)中傳遞,儘管大多數情況下被限制在單一實例中。
另一種是傳統的並發模型,多線程共享內存(基於共享變量的並發) , 會在後續單獨闡述。
goroutine
goroutine
是一個輕量級的線程 , 它與線程的區別是線程是操作系統中對於一個獨立運行實例的描述,不同的操作系統中,線程的實現也不盡相同;
對於 goroutine,操作系統並不知道它的存在 , goroutine
的調度是 Go 語言的運行時進行管理的。
啟動線程雖然比進程使用的資源少 , 但依然需要上下文切換等大量工作 , Go 語言有自己的調度器 , 許多 goroutine
的數據都是共享的 , 因此 goroutine
之間的切換會快很多 , 啟動 goroutine
所耗費的資源也很少。
|
|
channel
channel
被稱為通道 , 是連接並發 goroutine
的管道 , 可以從一個 goroutine
向通道發送值 , 並在另一個 goroutine
中接收到這些值 。
每個 channel
都有一個特殊的類型 , 也就是 channel
可發送數據的類型 。 一個可以發送 int
類型數據的 channel
一般寫為 chan int
。
一個 channel
有發送和接收兩個主要操作 , 都是通信行為 。
一個發送語句將一個值從一個 goroutine
通過 channel
發送到另一個執行接收操作的 goroutine 。
發送和接收兩個操作都是用 <-
運算符 。
在發送語句中 , <-
運算符分割 channel
和要發送的值 ; 在接收語句中 , <-
運算符寫在 channel
對象之前 , 一個不使用接收結果的接收操作也是合法的。
channel
的發送操作將導致發送者 goroutine
阻塞 , 直到另一個 goroutine
在相同的 channel
上執行接收操作 , 當發送的值通過 channel
成功傳輸之後 , 兩個 goroutine
可以繼續執行後面的語句 。
反之 , 如果接收操作先發生 , 那麼接收者 goroutine
也將阻塞 , 直到有另一個 goroutine
在相同的 Channels
上執行發送操作。
|
|
channel
還支持 close
操作 , 用於關閉 channel
, 隨後對基於該 channel
的任何發送操作都將導致 Panic
異常 。
對一個已經被 close
過的 channel
接收操作依然可以接受到之前已經成功發送的數據 ; 如果 channel
中已經沒有數據的話將產生一個零值(nil)的數據 。
|
|
帶緩存的 channel
帶緩存的 channel
內部有一個元素隊列 。 隊列的最大容量是在調用 make
函數創建 channel
時通過第二個參數指定的 。
下面的語法創建了一個可以持有三個字符串元素的帶緩存 channel
。
|
|
向緩存 channel
的發送操作就是向內部緩存隊列的尾部插入元素 , 接收操作則是從隊列的頭部刪除元素 。
如果內部緩存隊列是滿的 , 那麼發送操作將阻塞直到另一個 goroutine
執行接收操作而釋放了新的隊列空間。
相反,如果 channel
是空的 , 接收操作將阻塞直到有另一個 goroutine
執行發送操作而向隊列插入元素 。
|
|
select
Go 語言的 select
的功能和 select、poll、epoll
相似 , 就是監聽 IO 操作 , 當 IO 操作發生時 , 觸發響應的動作 。
select
語法和 switch
相似 , 也會有幾個 case
和 default
分支 , 每一個 case
代表一個通信操作(在某個 channel
上進行發送或者接收)並且會包含一些語句組成一個語句塊。
|
|
超時控制
select
是用來讓我們的程序監聽多個文件句柄的狀態變化的處理機制 。
當發起一些阻塞的請求後 , 可以用 select
機制輪詢掃描文件句柄 , 直到被監視的文件句柄有一個或多個發生了狀態改變。
channel
在系統層面來說也是個文件描述符 , 在 Go 語言中我們可以用 goroutine
並發執行任務 , 接著使用 select
來監視每個任務的 channel
情況 。
如果這幾個任務都長時間沒有回复 channel
信息 , 並且我們又有超時的需求 , 那麼我們可以使用一個 goroutine
來設置超時機制 , 具體做法就是啟動 sleep
並且在 sleep
之後回复 channel
信號。
|
|