1. 程式人生 > 實用技巧 >golang學習筆記---select(3)

golang學習筆記---select(3)

select 介紹

從不同併發執行的協程中,獲取資料可以用select來完成。select監聽的多個通道,也可以用通道傳送數值。

select {
// 接收資料
case u:= <- ch1:
        ...
// 傳送資料
case v:= <- ch2:
        ...
        ...
default: // no value ready to be received
        ...
}

select 基本用法

1、如果多個通道都阻塞了,會等待直到其中一個通道可以處理。
2、如果多個通道都可以處理,隨機選取一個處理。
3、如果沒有通道操作可以操作並且寫了default語句,會執行:default(永遠是可以執行的)

4、如果防止select堵塞,可以寫default來確保傳送不被堵塞,沒有case的select就會一直堵塞。
5、當select做選擇case和default操作時,case的優先順序大於default。
6、select語句實現了一種監聽模式,通常在無限迴圈中使用,通過在某種情況下,通過break退出迴圈

示例:
package main

import "fmt"

func main() {
	ch := make(chan int, 1)
	for i := 0; i < 10; i++ {
		select {
		case ch <- i:
		case x := <-ch:
			fmt.Println(x)
		}
	}
}

因為這個管道的緩衝值只有1,那麼同一時間只會有一個case執行,這個channel不是空的就是滿的。

在第一次進入迴圈的時候,i為0,進入到select中,開始由上向下來發現哪一個case可以執行,當計算表示式
ch <- i,也就是向管道寫入資料的時候,因為這個管道現在有緩衝,那麼在向管道寫完資料之後,此時的case便執行完成,然後就跳出select,開始進行下一次的迴圈,當i=1的時候(現在這個管道里面的資料是0),再次進入select中,此時還是開始計算ch <- i 表示式,但是現在管道里面是有資料的,再次向管道中寫入資料,那麼會使該傳送操作阻塞,此時該case便無法再執行,那麼select將會繼續向下執行下一個case,在下一個case中,有一個管道的接收操作x := <- ch,在這裡管道里有之前第一次迴圈的時候放入的0這個資料,那麼在這裡就會將管道的資料賦值給x,從而打印出第一個資料0,那麼後面的資料就和之前的過程是一樣的了。

看到這裡,大概就能明白select的作用了,順便說一下,select的case語句中,都是對應一個I/O操作,準確的說是對應一個channel的I/O操作,那麼到這裡也應該可以理解為什麼在code-1中,一個無緩衝的channel能在那段程式碼中產生一個deadlock