select

参考 https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-select/
Go 语言中的 select 关键字能够让 Goroutine 同时等待多个 Channel 的可读或者可写,在多个 Channel 发生状态改变之前,select 会一直阻塞当前线程或者 Goroutine。

当我们在 Go 语言中使用 select 控制结构时,会遇到两个有趣的现象:

  • select 能在 Channel 上进行非阻塞的收发操作;
  • select 在遇到多个 Channel 同时响应时会随机挑选 case 执行;

阻塞的情况

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

非阻塞的实际情况

errCh := make(chan error, len(tasks)
wg := sync.WaitGroup{}
wg.Add(len(tasks))
for i := range tasks {
    go func() {
        defer wg.Done()
        if err := tasks[i].Run(); err != nil {
            errCh <- err
        }
    }()
}
wg.Wait()

select {
case err := <-errCh:
    return err
default:
    return nil
}

在上面这段代码中,我们不关心到底多少个任务执行失败了,只关心是否存在返回错误的任务,最后的 select 语句就能很好地完成这个任务。