有时候,你可能发现你想要将多个 done channel 合并成一个单一的 done channel 来在这个符合 done channel 中的任意一个 channel 关闭的时候关闭整个 done channel。 编写一个执行这种耦合的选择语句是完全可以接受的,尽管很冗长。 但是,有时你无法知道你在运行时使用的 done channel 的数量,在这种情况下,或者你只喜欢单线程,你可以使用 or-channel 模式将这些 channel 组合在一起。
var or func(channels ...<-chan interface{}) <-chan interface{}
or = func(channels ...<-chan interface{}) <-chan interface{} {
switch len(channels) {
case 0:
return nil
case 1:
return channels[0]
}
orDone := make(chan interface{})
go func() {
defer close(orDone)
switch len(channels) {
case 2:
select {
case <-channels[0]:
case <-channels[1]:
}
default:
select {
case <-channels[0]:
case <-channels[1]:
case <-channels[2]:
// 很有意思的递归,实现了一个 channel 关闭程序,
case <-or(append(channels[3:], orDone)...):
}
}
}()
return orDone
}
sig := func(after time.Duration) <-chan interface{} {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
<-or(
sig(2*time.Hour),
sig(5*time.Minute),
sig(1*time.Second),
sig(1*time.Hour),
sig(1*time.Minute),
)
fmt.Printf("done after %v", time.Since(start))