最好在主 goroutine 里定义channel并准备初始数据,再根据需要发出子goroutine 实现具体处理逻辑,各子goroutine可以从 channel 接收数据和(或)往 channel 发送数据。
如果不是特殊需要,不要定义无缓冲的 channal,也不要在主goroutine里从channel里接收或往其发送数据。
原则上,由发送方主动关闭channel, 接收方通过影子变量得知channel是否关闭。
尽量使用无阻塞的的select 轮询,也就是select 语句块包含一个default 分支。无阻塞的select只是说select语句块不会被阻塞,任一case从 channel 接收或发送数据都有可能阻塞,任一时刻当所有case分支阻塞时,走default分支。为了多次轮询若干个 channel, 可以使用 for loop 循环调用无阻塞的 select。
如果无阻塞的select语句块作用在 unbuffered channel 上,会由于channel一直阻塞,goroutine 会直接从 default 分支走掉。建议使用 buffered channel 并且 capacity 足够大。
无阻塞的 select 最好有超时实现。如有需要,可调用time包的time.NewTimer(n * time.Second).C 返回一个绝对到期时间的通道,通道里包含的是绝对到期时间值。
如果需要类似回调功能,可以定义结构体A,其嵌套一个 channel 叫 resultChan,请求方 goroutineA 发送A到某个 channel 叫 messageChan,处理方 goroutineB 从 messageChan 里接收 A,处理好后将结果发送到 resultChan,goroutineA 从 resultChan 接收最终结果然后处理,完成回调。
比较常用的无阻塞读取数据的代码:
1 | aChannel := make(chan int, 3) |