一个数据聚合模块的工作协程将多个数据流合为一个数据流(就是指有多个源 channel 输入、一个目的 channel 输出的情况)。
下面这个函数将任意数量的数据流合为一个。
e.g.
通过每个 goroutine 处理一个 channel 的方式来实现。
go
func Aggregator(chs ...<-chan any) <-chan any {
out := make(chan any)
var wg sync.WaitGroup
for _, ch := range chs {
wg.Add(1)
ch := ch
go func() {
defer wg.Done()
for v := range ch {
out <- v
}
}()
}
go func() {
wg.Wait()
close(out)
}()
return out
}
e.g.
通过反射的方式来实现,主要就是构造出 SelectCase slice,然后传递给 reflect.Select 语句。
go
func AggregatorReflect(chs ...<-chan any) <-chan any {
out := make(chan any)
go func() {
defer close(out)
// 构造 SelectCase slice
var cases []reflect.SelectCase
for _, ch := range chs {
cases = append(cases, reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(ch),
})
}
// 循环,从 cases 中选择一个可用的
for len(cases) > 0 {
i, v, ok := reflect.Select(cases)
if !ok { // 此通道关闭并且它的缓冲队列中为空
cases = append(cases[:i], cases[i+1:]...)
continue
}
out <- v.Interface()
}
}()
return out
}