go中的select

go中的select提供了一種方式來處理多個channels,select語句滿足如下條件

  1. 每個channel的值都會被計算
  2. 如果沒有channel有產出的話,會阻塞直到一個channel產出
  3. 如果多個channel有產出的話,會假隨機(pseudo-randomly)的選擇一個產出
  4. 在有default語句的情況下,沒有channel準備好的時候,會立即執行default的語句

下面有一個實例,源碼中對boring返回結果的註釋(第一行末尾的註釋)直譯是返回一個只接受string類型的channel。但是個人覺得翻譯爲返回的是一個只讀的string類型的channel更好,因爲後續的對c的操作,都只能從c中讀取string

func boring(msg string) <-chan string { // Returns receive-only channel of strings.
    c := make(chan string)
    go func() { // We launch the goroutine from inside the function.
        for i := 0; ; i++ {
            c <- fmt.Sprintf("%s %d", msg, i)
            time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
        }
    }()
    return c // Return the channel to the caller.
}
func fanIn(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    go func() {
        for {
            select {
            case s := <-input1:  c <- s
            case s := <-input2:  c <- s
            }
        }
    }()
    return c
}
func main() {
	joe := boring("Joe")
	ann := boring("Ann")
	c := fallin(joe, ann)
	for i := 0; i < 20; i++ {
		fmt.Println(<-c)
	}
	fmt.Println("You're both boring; I'm leaving.")
}

產生的結果如下,其中由於每個boring中的sleep的時間不確定,所以導致結果是Joe最終對應的i爲10,而Ann最終對應的i爲8

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Ann 3
Joe 4
Ann 4
Joe 5
Ann 5
Joe 6
Ann 6
Ann 7
Joe 7
Joe 8
Joe 9
Ann 8
Joe 10
You're both boring; I'm leaving.

select語句滿足的條件1是值得思考的,每個channel都是需要計算取值的,因爲沒有正確的理解這句話是可能犯錯誤的。
可以思考下面這個函數的輸出,三秒之後函數會停止執行嗎?

func main() {
	c := boring("Joe")
	for {
		select {
		case s := <-c:
			fmt.Println(s)
		case <- time.After(3 * time.Second):
			fmt.Println("Your're too slow")
			return
		}
	}
}

答案是不會的,因爲每次執行到select語句中的各個選項的時候,都會計算每個case中的值。相當於在第一次輸出c的產出之後,第二次進入select的選擇的時候,time.After()就又重新開始計時了。要想在三秒之後停止這個函數,需要調整time.After的位置到select執行之前。

func main() {
	c := boring("Joe")
    timeout := time.After(3 * time.Second)
	for {
		select {
		case s := <-c:
			fmt.Println(s)
		case <- timeout:
			fmt.Println("Your're too slow")
			return
		}
	}
}

本文內容翻譯自 Go Concurrency Patterns
做一個知識型討飯的,有些閒錢的,覺得對你有用的可以捐點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章