網頁

2021/10/1

Golang select 用法

Go select的用法如下。


Go select可在多個channel的send(發送)或receive(接收)隨機選擇一個來執行。

例如下面建立了兩個channel c1c2,各以goroutine把值送入,接著用time.Sleep()暫時一秒確保前面的goroutine先於後面的select執行。在for迴圈中用select的case選擇從channel接收資料放入變數s,若沒可執行的channel操作則走default離開迴圈。

package main

import (
    "fmt"
    "time"
)

func main() {
    c1 := make(chan string)
    c2 := make(chan string)

    go func() {
        c1 <- "a"
    }()

    go func() {
        c2 <- "b"
    }()
    time.Sleep(time.Second)

L:
    for {
        var s string
        select {
        case s = <-c1:
        case s = <-c2:
        default:
            break L
        }
        fmt.Println(s)
    }

}

因為select敘述是隨機選擇channel的send或receive操作來執行,所以可能先印出a然後b,也有可能先印出b然後印出a。


select的另一個特性是若選擇的channel操作被阻塞且又沒有default時,則select會等待直到該channel可執行為止。

例如下面select總是先印出b,阻塞一秒才印出a。第一個goroutine中的time.Sleep()等待一秒才發送值給channel c1,所以在第一次迴圈select會先走<-c2;第二次迴圈走<-c1時(因為c2已經空了)由於time.Sleep()值未送入c1,因此select會先阻塞暫停,直到time.Sleep()結束執行c1 <- "a"後select才繼續<-c1

package main

import (
    "fmt"
    "time"
)

func main() {
    c1 := make(chan string)
    c2 := make(chan string)

    go func() {
        time.Sleep(time.Second)
        c1 <- "a"
    }()

    go func() {
        c2 <- "b"
    }()

    for i := 0; i < 2; i++ {
        var s string
        select {
        case s = <-c1:
        case s = <-c2:
        }
        fmt.Println(s)
    }

}


沒有留言:

張貼留言