Golang: Language: Concurrency: Select Dynamic Channels

 9th February 2022 at 4:08pm

Go 的 select 语句可以选中多个已知的 channel 变量。但是假如你要 select 的 channel 并不是固定的,比如放在一个 slice 中,那么你需要用 reflect.Select 函数来实现。

这个函数不难理解。这里有一个简单的代码例子:

package main

import (
	"fmt"
	"reflect"
	"time"
)

func main() {
	var cases []reflect.SelectCase
	var chs []chan int
	for i := 0; i < 4; i++ {
		chs = append(chs, make(chan int, 10))
		cases = append(cases, reflect.SelectCase{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(chs[i]),
		})
	}

	go func() {
		n := 0
		for {
			for i := 0; i < 4; i++ {
				chs[i] <- n
				n++

				time.Sleep(1 * time.Second)
			}
		}
	}()

	for {
		i, v, ok := reflect.Select(cases)
		fmt.Printf("Chan %d: received %d, %t\n", i, v.Int(), ok)
	}
}

需要注意的是,如果 cases 中有 closed 的 recv channel,reflect.Select() 会马上返回,其中 v 为该 channel 的数据类型的零值(比如 chan int 对应的是 0),ok 为 false。

还没有实验 send 数据到一个 closed channel 会有什么表现。