1. 程式人生 > >Go關鍵字--select

Go關鍵字--select

select

在golang中使用select可以實現一個條件選擇器,select與switch關鍵字有著類似的效果,都是實現了一個條件選擇器,但是select中的判斷條件必須是通訊操作,golang中的通訊操作是 <- 。當通道在操作符左側時,表示向通道中寫入資訊,當通道在操作符右側時,表示讀取通道資訊。

// 寫入操作
通道 <-// 讀取操作
變數 <- 通道

編寫select條件選擇器的語法格式是:

select {
    case <- ch1:
        // 讀取通道ch1,讀取成功,執行這個分支。
        // do something
    case
val := <- ch2: // 讀取通道ch2,讀取成功,執行這個分支。 // do something case ch3 ->: // 想 // do something default: // do something }

在golang中,支援通訊操作的型別只有chan,所以select中的case條件只能是對chan型別變數的讀寫操作。由於chan型別變數的讀寫操作可能會引起阻塞,為了在使用select選擇器時不陷入阻塞狀態,可以在select程式碼塊中新增default關鍵字,當case條件全部都不滿足時,預設進入default分支,執行完default分支的程式碼後,退出select選擇器。

下邊來一個例子來使用select實現條件選擇。

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("開始時間:", time.Now().Format("2006-01-02 15:04:05"))
	select {
	case <-time.After(time.Second * 2):
		fmt.Println("2秒後的時間:", time.Now().Format("2006-01-02 15:04:05"))
	}
}

輸出資訊是:

開始時間: 2017-09-15 23:23:10
2秒後的時間: 2017-09-15 23:23:12

time.After函式返回一個通道型別的變數,然後在case中從這個通道中讀取資訊,如果沒有協程給這個通道傳送資訊,那麼case將會一直阻塞。在呼叫After函式時,傳入了一個時長作為引數,意思是從呼叫After函式算起,到設定的市場後,有協程將會向這個通道傳送一條訊息。當通道收到訊息後,這個case條件滿足,這個case分支下的程式碼將會被執行。

當select中同一時間,有多個case滿足條件時,select會選擇哪一個分支執行,還是執行多個分支呢?答案是:隨機選擇一個滿足滿足條件的case分支執行,這個分支執行完成後,退出select選擇器。請記住:是隨機選擇一個滿足條件的case分支執行。下邊請看示例:

package main

import (
	"fmt"
	"time"
)

func main() {
	var ch1 chan int = make(chan int)
	var ch2 chan int = make(chan int)

	go func() {
		fmt.Println("從通道ch2中讀取資料:", <-ch2)
	}()

	go func() {
		ch1 <- 88
	}()

	select {
	case <-time.After(time.Second * 5):
		// do something
		fmt.Println("timeout")
	case val := <-ch1:
		fmt.Println("從通道ch1中讀取資料", val)
		//  do something
	case ch2 <- 99:
		// do something
	}
	time.Sleep(time.Second * 2)
}

輸出資訊有兩種情況,一種是:

從通道ch2中讀取資料: 99

另一種是:

從通道ch1中讀取資料 88