全面解析 Go 語言 Channel:面試必備知識點
一、channel 的整體結構圖
1、channel 結構圖
- channel 本質是一個 hchan 這個結構體
type hchan struct {
buf unsafe.Pointer // points to an array of dataqsiz elements
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
lock mutex
}
-
簡單說明:
-
buf 是有緩衝的 channel 所特有的結構,用來存儲緩存數據,是哥循環鏈表
-
sendx 和 recvx 用於記錄 buf 這個循環鏈表中的發送或者接收的 index
-
recvx 和 sendx 是根據循環鏈表 buf 的變動而改變的
-
lock 是個互斥鎖,發送或接收前都需要加鎖
-
recvq 和 sendq-> 是個雙向鏈表
-
分別是接收或者發送的 goroutine 抽象出來的結構體 (sudog) 的隊列
**2、創建 channel
**
-
創建 channel 實際上就是在內存中實例化一個 hchan 的結構體,並返回一個 ch 指針
-
我們使用過程中 channel 在函數之間的傳遞都是用的這個指針
-
這就是爲什麼函數傳遞中無需使用 channel 的指針,而直接用 channel 就行了,因爲 channel 本身就是一個指針
3、channel 中隊列如何實現
-
channel 中有個緩存 buf,是用來緩存數據的 (假如實例化了帶緩存的 channel 的話) 隊列
-
當使用
send (ch <- xx)或者recv ( <-ch)的時候,首先要鎖住hchan這個結構體 -
然後開始
send (ch <- xx)數據,這時候滿了,隊列塞不進去了 -
然後是取
recv ( <-ch)的過程,是個逆向的操作,也是需要加鎖
4、channel 緩存滿發生什麼
-
使用的時候,我們都知道,當 channel 緩存滿了,或者沒有緩存的時候
-
我們繼續 send(ch <- xxx) 或者 recv(<- ch) 會阻塞當前 goroutine,但是,是如何實現的呢?
-
Go 的 goroutine 是用戶態的線程 (user-space threads),用戶態的線程是需要自己去調度的
-
Go 有運行時的 scheduler 去幫我們完成調度這件事情
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/JLhN9azPrqLtv3qLCc9VKg