0%

Go Concurrency programming Select

Select就是ChannelSwitch. Select具备一系列的Case分支和一个默认default分支, 每一个case对应于一个channel操作(send/receive). select在多case场景下会一直等待, 直到某个case操作完成, 就会执行case内对应的语句.

代码示例:

1
2
3
4
5
6
7
8
select {
case <-chan1:
// 如果chan1成功读到数据,则进行该case处理语句
case chan2 <- 1:
// 如果成功向chan2写入数据,则进行该case处理语句
default:
// 如果上面都没有成功,则进入default处理流程
}

特点:

  • select可以同时监听一个或多个channel, 直到某个channel操作完成;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package main

    import (
    "fmt"
    "time"
    )

    func main() {
    ch1 := make(chan int)
    ch2 := make(chan string)
    go sender1(ch1)
    go sender2(ch2)
    select {
    case value := <-ch1:
    fmt.Printf("Got from channel one: %v \n", value)
    case value := <-ch2:
    fmt.Printf("Got from channel two: %v \n", value)
    }

    time.Sleep(1 * time.Second)
    }

    func sender1(ch chan int) {
    ch <- 1
    }

    func sender2(ch chan string) {
    ch <- "Qingzhi"
    }

    上面定义了两个case, 分别从ch1, ch2两个channel进行接收操作, 满足操作则进行打印操作;

  • 多个case同时满足时, 随机选择一个case执行, 其他case不执行;

    select前通过sleep操作保证多case同时满足, 多次运行,可以发现输出结果时随机的.

  • default case一般用于非阻塞的case.

  • 一般通过time.After设置超时器.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    package main

    import (
    "fmt"
    "time"
    )

    func main() {
    ch1 := make(chan int)
    ch2 := make(chan string)
    go sender1(ch1)
    go sender2(ch2)
    select {
    case value := <-ch1:
    fmt.Printf("Got from channel one: %v \n", value)
    case value := <-ch2:
    fmt.Printf("Got from channel two: %v \n", value)
    case <-time.After(1 * time.Second):
    fmt.Printf("Time out \n")
    }

    time.Sleep(1 * time.Second)
    }

    func sender1(ch chan int) {
    time.Sleep(2 * time.Second)
    ch <- 1
    }

    func sender2(ch chan string) {
    time.Sleep(2 * time.Second)
    ch <- "Qingzhi"
    }

    通过time.After可以获得一个仅能够接收的channel, 这样可以手动设置超时器, 防止程序挂起.