上一篇 Go聖經-學習筆記之併發循環golang
這個概念與socket網絡編程中的select、poll和epoll中的select概念相似。其含義是有N個channel,只要有一個channel上有數據產生,select就會當即監聽到,而後接收數據,處理數據,若是有多個channel隊列上都有數據流,則隨機選取一個channel;若是N個channel上都沒有數據流,則一直髮生阻塞。例如, 火箭既能夠倒計時發射,也能夠在倒計時期間取消發射:面試
// 倒計時 func countdown(count chan struct{}) { tick:=time.Tick(1*time.Second) for i:=10; i>0; i-- { fmt.Printf("countdown: %d\n", i) <-tick } count<-struct{}{} return } // 中斷髮射 func abort(ach chan struct{}) { os.Stdin.Read(make([]byte, 1)) ach<- struct{}{} return } func main() { var count = make(chan struct{}) var ach = make(chan struct{}) go countdown(count) go abort(ach) select { case <-count: launch() case <-ach: fmt.Println("abort launch...") } return }
也能夠使用time.After(10*time.Second)
, 也表示10s後發射。這個例子其實有goroutine泄露,由於tick所在的發送端是一個未知的goroutine,它會每隔1s會向tick channel發送一個數據。程序結束時,也沒有關閉goroutine。除非是程序隱式地作。編程
// 一個更友善的方法: ticker := time.NewTimer(1*time.Second) <-ticker.C ticker.Stop() // 它會觸發timer的goroutine主動退出
在使用select時,常常用到的一個場景就是web服務處理請求,若是一個請求處理的時間過長或者負載太高致使的處理時間過長,它會拖慢整個服務端性能,這時候應該儘早讓處理時間過長的請求去釋放資源。網絡
select { case <-ch1: // ch1所在的發送端goroutine正在處理請求 case <-time.After(2*time.Second): // 釋放資源,返回請求處理失敗的數據,或者先通知用戶已處理成功,最終一致性能夠保證。 // 最重要的是快速響應,省得用戶看着頁面沒反應,過多的點擊按鈕發送請求,會過多消耗服務端的系統資源 }
ch := make(chan int, 1) for i := 0; i < 10; i++ { select { case x := <-ch: fmt.Println(x) case ch <- i: } }
問輸出結果是什麼?併發
結果:"0" "2" "4" "6" "8", 由於select多路複用中的兩個channel實際上是同一個,一個用來發送,一個用來接收。因此每當執行ch<-i
都是跳躍的,因此每次往ch中發送數據都是偶數了。socket