您好,登錄后才能下訂單哦!
本篇內容主要講解“Go select使用與底層原理是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Go select使用與底層原理是什么”吧!
select 是 Go 提供的 IO 多路復用機制,可以用多個 case 同時監聽多個 channl 的讀寫狀態:
case: 可以監聽 channl 的讀寫信號
default:聲明默認操作,有該字段的 select 不會阻塞
select { case chan <-: // TODO case <- chan: // TODO default: // TODO }
每一個 case 對應的 channl 都會被封裝到一個結構體中;
當第一次執行到 select 時,會鎖住所有的 channl 并且,打亂 case 結構體的順序;
按照打亂的順序遍歷,如果有就緒的信號,就直接走對應 case 的代碼段,之后跳出 select;
如果沒有就緒的代碼段,但是有 default 字段,那就走 default 的代碼段,之后跳出 select;
如果沒有 default,那就將當前 goroutine 加入所有 channl 的對應等待隊列;
當某一個等待隊列就緒時,再次鎖住所有的 channl,遍歷一遍,將所有等待隊列中的 goroutine 取出,之后執行就緒的代碼段,跳出select。
每一個 case 對應的數據結構如下:
type scase struct { c *hchan // chan elem unsafe.Pointer // 讀或者寫的緩沖區地址 kind uint16 //case語句的類型,是default、傳值寫數據(channel <-) 還是 取值讀數據(<- channel) pc uintptr // race pc (for race detector / msan) releasetime int64 }
學習了 select 的使用與原理,我們就能更輕松地分辨不同情況下的輸出情況了。
package main import ( "fmt" "time" ) func main() { chan1 := make(chan int) chan2 := make(chan int) go func() { chan1 <- 1 time.Sleep(5 * time.Second) }() go func() { chan2 <- 1 time.Sleep(5 * time.Second) }() select { case <- chan1: fmt.Println("chan1") case <- chan2: fmt.Println("chan2") default: fmt.Println("default") } }
三種輸出都有可能。
package main import ( "fmt" "time" ) func main() { chan1 := make(chan int) chan2 := make(chan int) select { case <- chan1: fmt.Println("chan1") case <- chan2: fmt.Println("chan2") } fmt.Println("main exit.") }
上述程序會一直阻塞。
package main import ( "fmt" ) func main() { chan1 := make(chan int) chan2 := make(chan int) go func() { close(chan1) }() go func() { close(chan2) }() select { case <- chan1: fmt.Println("chan1") case <- chan2: fmt.Println("chan2") } fmt.Println("main exit.") }
隨機執行1或者2.
package main func main() { select { } }
對于空的 select 語句,程序會被阻塞,確切的說是當前協程被阻塞,同時 Go 自帶死鎖檢測機制,當發現當前協程再也沒有機會被喚醒時,則會發生 panic。所以上述程序會 panic。
到此,相信大家對“Go select使用與底層原理是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。