在Go101站点的this article中,我已经阅读了stopCh
频道的双重选择的一些技巧(在“ 2.一个接收者,N个发送者,唯一的接收者说:请停止发送更多”关闭另一个信号通道”)。
请您描述一下它的工作原理,我真的需要在实际应用中使用它吗?
UPD :我没有询问有关频道关闭的问题。我询问了这部分代码的用法:
// The try-receive operation is to try
// to exit the goroutine as early as
// possible. For this specified example,
// it is not essential.
select {
case <- stopCh:
return
default:
}
// Even if stopCh is closed, the first
// branch in the second select may be
// still not selected for some loops if
// the send to dataCh is also unblocked.
// But this is acceptable for this
// example, so the first select block
// above can be omitted.
select {
case <- stopCh:
return
case dataCh <- rand.Intn(Max):
}
双重选择stopCh
的真正用例是什么?
答案 0 :(得分:2)
这里的关键是要了解如果可以继续进行多种情况(即伪随机),select的行为方式:
- 如果可以进行一种或多种通信,则可以通过统一的伪随机选择来选择可以进行的单个通信。
https://golang.org/ref/spec#Select_statements
select {
case <- stopCh:
return
case dataCh <- rand.Intn(Max):
}
仅使用第二个select语句,在stopCh
关闭之后,如果满足以下至少一项要求,则两种情况都可能继续进行:
dataCh
已关闭,至少有一个goroutine尝试从stopCh
接收如果没有明确检查stopCh
,则可能(尽管不太可能)运行时会重复选择第二种情况,即使希望goroutine退出。如果goroutine每次发射时都碰巧发射了导弹,那么您会发现这可能是个问题。
如果可以肯定地排除这两种情况,则可以省略第一个select语句,因为不可能同时准备好两种情况。 Go101文章只是展示了一个保证工作的解决方案,而无需做任何假设。
此模式在实际代码中并不罕见,通常与上下文取消有关:
func f(ctx context.Context, ch chan T) {
for {
// Make sure we don't shoot after ctx has been
// canceled, even if a target is already lined up.
select {
case <-ctx.Done():
return
default:
}
// Or, equivalently: if ctx.Err() != nil { return }
select {
case <-ctx.Done():
return
case t := <-ch:
launchMissileAt(t)
}
}
}