我最近开始学习go,并试图了解通道是如何工作的。我正在那里读一本书,他们给了这样一个例子:
有时您将使用来自系统不同部分的通道。与管道不同,您不能断言通道的行为当你正在处理的代码通过它的done通道被取消时。也就是说,你不知道你的节目被取消是否意味着你的频道阅读将被取消。出于这个原因,我们需要用select语句包装从通道读取的内容,该语句也从done通道中进行选择。这很好,但是这样做需要很容易读懂的代码,如
func orDone(done, c <-chan interface{}) <-chan interface{} {
valStream := make(chan interface{})
go func() {
defer close(valStream)
for {
select {
case <-done:
return
case v, ok := <-c:
if ok == false {
return
}
select {
case valStream <- v:
case <-done:
fmt.Println("inside", count)
}
}
}
}()
return valStream
}
我不太明白通过一个完成的频道关闭一个频道是如何工作的。假设我有这样的代码:
func main() {
done1 := make(chan interface{})
done2 := make(chan interface{})
inf := infGenerator(done1)
for v := range orDone(done2, inf) {
if count == 3 {
close(done1)
}
count++
fmt.Println(v)
}
}
例如,如果第一个通道关闭,那么一切都是清楚的,它将被执行
if ok == false {
return
}
但是我不太明白当我们关闭第二个通道而不是第一个通道时,程序是如何工作的。
首先,程序进入
case <-done:
fmt.Println("inside", count)
}
然后它进入上面的那个。我不明白为什么会这样。嵌套的case <-done:
不应该获取闭包消息并拾取它吗?或者如果我们关闭信道,那么它的信号不会从信道中获取?如果有可能在结束时执行另一个案例呢?
假设infGenerator
关闭inf
接到done
信号:
关闭done1
会导致关闭inf
,从而导致orDone
返回您所说的。
如果关闭done
,函数orDone
执行嵌套的done
,然后执行外部的done
,仅仅是因为嵌套的done
没有从函数返回。它读取done
信号,继续循环,循环再次读取done
信号并返回。
未缓冲的通道不包含任何数据。因此,如果您关闭了一个未缓冲的通道,任何被阻塞的从该通道读取的程序都将通过false
启用。任何进一步的读取尝试也将立即返回false
。因此,关闭通道是向所有例程广播完成的好方法。