Go聖經-學習筆記之select多路複用

上一篇 Go聖經-學習筆記之併發循環golang

下一篇 Go聖經-學習筆記之併發的字典遍歷web

select多路複用

這個概念與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):
        // 釋放資源,返回請求處理失敗的數據,或者先通知用戶已處理成功,最終一致性能夠保證。
        // 最重要的是快速響應,省得用戶看着頁面沒反應,過多的點擊按鈕發送請求,會過多消耗服務端的系統資源
}

面試題select

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

相關文章
相關標籤/搜索