我有两个goroutines独立产生数据,每个将它们发送到一个通道。在我的主要goroutine中,我想在输入这些输出时使用它们,但是不在乎它们的输入顺序。每个通道在耗尽其输出时都会自行关闭。虽然select语句是用于像这样独立使用输入的最佳语法,但是直到两个通道都关闭之前,我还没有看到一种简洁的循环方法。
for { select { case p, ok := <-mins: if ok { fmt.Println("Min:", p) //consume output } case p, ok := <-maxs: if ok { fmt.Println("Max:", p) //consume output } //default: //can't guarantee this won't happen while channels are open // break //ideally I would leave the infinite loop //only when both channels are done } }
我能想到的最好的方法是以下操作(只是草绘,可能会有编译错误):
for { minDone, maxDone := false, false select { case p, ok := <-mins: if ok { fmt.Println("Min:", p) //consume output } else { minDone = true } case p, ok := <-maxs: if ok { fmt.Println("Max:", p) //consume output } else { maxDone = true } } if (minDone && maxDone) {break} }
但是,如果您使用的通道超过两个或三个,这看起来将变得站不住脚。我知道的唯一另一种方法是在switch语句中使用一个timout情况,该情况可能足够小以至于有可能提前退出,或者将太多的停机时间注入到最终循环中。有没有更好的方法来测试通道是否在select语句中?
那么,我该如何解决这个问题呢?零通道永远不会准备好进行通信。因此,每次遇到封闭频道时,您都可以将该频道设为零,以确保不再选择该频道。此处的可运行示例:http ://play.golang.org/p/8lkV_Hffyj
for { select { case x, ok := <-ch: fmt.Println("ch1", x, ok) if !ok { ch = nil } case x, ok := <-ch2: fmt.Println("ch2", x, ok) if !ok { ch2 = nil } } if ch == nil && ch2 == nil { break } }
至于担心它变得笨拙,我认为它不会。很少有频道一次转到太多地方的情况很少。这很少出现,我的第一个建议就是解决这个问题。较长的if语句将10个通道与nil进行比较,并不是试图在一个选择中处理10个通道的最糟糕的部分。