有时候你可能想分割来自通道的多个值,以便将它们发送到两个独立区域。想象一下:你可能想要在一个通道上接收一系列操作指令,将它们发送给执行者,同时记录操作日志。
与Unix系统的tee命令功能类似,我们用tee-channel来实现同样的功能。你可以传递给它一个用作读取的通道,它会返回两个单独的通道:
tee := func(
done <-chan interface{},
in <-chan interface{},
) (_, _ <-chan interface{}) { <-chan interface{}) {
out1 := make(chan interface{})
out2 := make(chan interface{})
go func() {
defer close(out1)
defer close(out2)
for val := range orDone(done, in) {
var out1, out2 = out1, out2 //1
for i := 0; i < 2; i++ { //2
select {
case <-done:
case out1 <- val:
out1 = nil //3
case out2 <- val:
out2 = nil //3
}
}
}
}()
return out1, out2
}
注意:原文例子就是这样,反复确认没有贴错。大家就当伪码看吧
- 我们希望使用使用本地的变量,所以建立了他们的副本。
- 我们将使用一条select语句,以便写入out1和out2不会彼此阻塞。 为了确保两者都顺利写入,我们将执行select语句的两个迭代。
- 一旦我们写入了通道,我们将其副本设置为零,这样继续写入将阻塞,而另一个通道可以继续执行。
注意写入out1和out2是紧密耦合的。 直到out1和out2都被写入,迭代才能继续。 通常这不是问题,因为无论如何,处理来自每个通道的读取流程的吞吐量应该是tee之外的关注点,但值得注意。 这是一个快速调用示例:
done := make(chan interface{})
defer close(done)
out1, out2 := tee(done, take(done, repeat(done, 1, 2), 4))
for val1 := range out1 {
fmt.Printf("out1: %v, out2: %v\n", val1, <-out2)
}
利用这种模式,很容易使用通道作为系统数据的连接点。
最后编辑: kuteng 文档更新时间: 2021-01-02 17:30 作者:kuteng