伙计们,我想知道如果我只有一种情况(我的频道)并用给定频道的关闭来表示结束,是否最好在频道范围内进行选择或使用选择?
举例:
go func() {
for v := range ch {
// do some stuff
}
}()
go func() {
for {
select {
case v, ok := <-ch:
if !ok {
return
}
// do some stuff
}
}
}()
哪种解决方案是首选,为什么?请考虑这样一个事实:goroutine 本身可能会产生很多次(很多工作线程)。
除非有另一个选择分支,否则使用以下内容:
for v := range ch {
// do some stuff
}
代码比问题中提出的 for/select 更简单、更容易理解。
如果由于某种原因需要在循环内进行接收,请使用以下代码:
for {
// do some stuff
v, ok := <-ch
if !ok {
break
}
// do some other stuff
}
根据经验,应避免使用单分支选择语句。具有单个分支的选择在功能上与单独的分支相同。
如果您只是在不需要返回值的完成通道上等待,那么您可以完全放弃 for 循环,因为 chan 将阻塞。例如
// Verbose
go func() {
for {
select {
case <-blah.Context.Done():
// Cleanup/Close
return
}
}
}()
// Simplified
go func() {
<-blah.Context.Done():
// Cleanup/Close (No return required either)
}()
我注意到使用 select 而不是 range 有一个区别,即使是单个通道。当接收到信号并触发关闭通道并重新分配它的代码逻辑时,范围循环将停止,因为通道已关闭。使用 for select 它将继续并在分配给该变量的新通道上运行。
在我的例子中,我使用 select 重新连接到 RabbitMQ 服务器。您可以在那里注册一个在连接关闭时接收信号的通道。然而,当连接关闭时,通道也会关闭,因此再次连接时需要重新声明它。因此,在我的情况下范围是不可行的,因为它停止了重新连接循环。