select為golang提供了多路io復用機制,和其他io復用一樣,用於檢測是否有讀寫事件是否ready。
本文將介紹一下golang的select的用法和實現原理。
golang實現select的時候,實際上為每乙個case語句定義了乙個資料結構,select語句塊執行的時候,實際上可以模擬成對乙個case陣列處理的**塊(或者函式),然後程式流程轉到選中的case塊。
原始碼包src/runtime/select.go:scase
定義了表示case語句的資料結構:
type scase struct
scase.c表示當前case語句操作的chan指標,這也表明乙個case只能監聽乙個chan。
scase.kind表示當前的chan是可讀還是可寫channel或者是default。三種型別分別由常量定義:
原始碼包src/runtime/select.go:selectgo()
定義了select選擇case的函式:
// selectgo implements the select statement.//// *sel is on the current goroutine's stack (regardless of any
// escaping in selectgo).
//// selectgo returns the index of the chosen scase, which matches the
// ordinal position of its respective select call.
func selectgo(sel *hselect) int
其中資料結構hselect如下:
// select statement header.// known to compiler.
// changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
type hselect struct
hselect.tcase存的是scase總數。
hselect.pollorder是儲存scase的隨機後的序列。以達到隨機檢測case的目的。
hselect.lockorder是儲存的channel位址。所有case語句中channel序列,以達到去重防止對channel加鎖時重複加鎖的目的。
selectgo返回int,表示選中的scase,也就是ready的channel index。
該函式執行邏輯大致如下:
1. 鎖定scase語句中所有的channel
2. 按照隨機順序檢測scase中的channel是否ready
2.1 如果case可讀,則讀取channel中資料,解鎖所有的channel,然後返回(case index)
2.2 如果case可寫,則將資料寫入channel,解鎖所有的channel,然後返回(case index)
2.3 所有case都未ready,則解鎖所有的channel,然後返回(default index)
3. 所有case都未ready,且沒有default語句
3.1 將當前協程加入到所有channel的等待佇列
3.2 當將協程轉入阻塞,等待被喚醒
4. 喚醒後返回channel對應的case index
4.1 如果是讀操作,解鎖所有的channel,然後返回(case index)
4.2 如果是寫操作,解鎖所有的channel,然後返回(case index)
Golang利用select實現超時機制
所謂超時,比如上網瀏覽一些安全的 如果幾分鐘之後不做操作,那麼就會讓你重新登入。就所謂有時候出現goroutine阻塞的情況,那麼我們如何避免整個程式進入阻塞情況,這時候就可以用select來設定超時 package main import fmt time func main 別忘了 for i ...
Golang併發模型 select高階
最近公司工作有點多,golang的select高階就這樣被拖沓啦,今天堅持把時間擠一擠,把吹的牛皮補上。前一篇文章 golang併發模型 輕鬆入門select 介紹了select的作用和它的基本用法,這次介紹它的3個高階特性。nil的通道永遠阻塞 如何跳出for selectselect 阻塞 當c...
golang開發 select多路選擇
select 是 golang 中的乙個控制結構,語法上類似於switch 語句,只不過select是用於 goroutine 間通訊的 每個 case 必須是乙個通訊操作,要麼是傳送要麼是接收,select 會隨機執行乙個可執行的 case。如果沒有 case 可執行,goroutine 將阻塞,...