在this article从 Go101 站点,我已经阅读了一些关于 stopCh
channel 的双重选择的技巧(在“2. 一个接收者,N 个发送者,唯一的接收者通过关闭一个额外的信号 channel ”说“请停止发送更多”部分) ).
您能否描述一下它是如何工作的,我真的需要在实际应用中使用它吗?
UPD:我没有询问 channel 关闭。我问过这部分代码的用法:
// 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
的实际用例是什么?
最佳答案
这里的关键是了解如果可以进行多种情况,即伪随机,select 的行为如何:
- If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection.
https://golang.org/ref/spec#Select_statements
select {
case <- stopCh:
return
case dataCh <- rand.Intn(Max):
}
只有第二个 select 语句,在 stopCh
关闭后,如果至少满足以下条件之一,则两种情况都可以继续进行:
- dataCh 已缓冲且未满
- 即使在
stopCh
关闭后,至少有一个 goroutine 尝试从dataCh
接收数据
如果不显式检查 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)
}
}
}
关于go - 了解 Go 中优雅的 channel 关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55709797/