淺談Golang中select的用法

在go中,select主要是和channel有關,大概的格式以下:code

select{
case <- ch1:
// do something
case i := <- ch2
// use i do something
default:
// ...
}

這個語法看起來和switch語句很接近,可是具體select有什麼用呢?咱們來看一段代碼:it

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

這段代碼裏咱們先建立了一個channel(管道),這個管道是無緩衝的,那麼這段代碼是否能正常的運行呢?select

答案是不能的,這段代碼會產生一個deadlock循環

那麼咱們稍微修改一下這個代碼,語法

ch := make(chan int, 1)

在這裏咱們將剛纔無緩衝的管道改變爲有緩衝且緩衝大小爲1的管道,再次運行以後,會顯示正確的結果,可是這個結果比較微妙:channel

0
2
4
6
8

由於這個管道的緩衝值只有1,那麼同一時間只會有一個case執行,這個channel不是空的就是滿的。
因此這個結果是比較固定的,可是爲何只會輸出這麼幾個數字呢?那咱們來一塊兒看看具體是怎麼運行的。goroutine

在第一次進入循環的時候,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分享

這裏還引出幾個概念:channel, buffer channel, goroutine等。時間

OK!今天就先到這裏,下次再繼續分享Golang的特點之一,goroutine

相關文章
相關標籤/搜索