golang的select實現原理剖析

2022-08-16 00:30:19 字數 1808 閱讀 9928

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 將阻塞,...