给定Go语言中一个(部分)填充的缓冲通道
ch := make(chan *MassiveStruct, n)
for i := 0; i < n; i++ {
ch <- NewMassiveStruct()
}
字符串
在不知道读取器何时将从通道读取的情况下,在关闭通道(由写入器)时也排空通道(例如,数量有限,并且它们当前正忙碌)。那就是
close(ch)
for range ch {}
型
如果通道上有其他并发读取器,是否保证这样的循环结束?
上下文:一个具有固定数量的工作线程的队列服务,当服务停止时(但不一定立即进行GCed),它应该放弃处理任何排队的东西。所以我关闭,以表明工人的服务正在终止。我可以立即清空剩余的“队列”,让GC释放分配的资源,我可以读取并忽略worker中的值,我可以让通道运行在读取器中,并在写入器中将通道设置为nil,以便GC清理所有内容。我不知道哪种方式最干净。
3条答案
按热度按时间xeufq47z1#
这取决于你的程序,但一般来说,我倾向于说不(你不需要在关闭它之前清除通道):如果在关闭通道时通道中有项目,则仍在从通道阅读的任何读取器将接收项目,直到通道为空。
下面是一个例子:
字符串
在这里,程序将输出所有项,尽管在任何读者可以从通道读取之前通道被严格关闭。
vsdwdz232#
有更好的方法来实现你想要实现的目标。您当前的方法可能会导致丢弃一些记录,并随机处理其他记录(因为耗尽循环正在与所有消费者竞争)。这并没有真正解决目标。
你想要的是取消。下面是一个来自Go Concurrency Patterns: Pipelines and cancellation的示例
字符串
你给所有的goroutine传递一个
done
通道,当你想让它们都停止处理时,你就关闭它。如果您经常这样做,您可能会发现golang.org/x/net/context
包很有用,它将这种模式形式化,并添加了一些额外的特性(如超时)。eanckbw93#
我觉得所提供的答案实际上并没有澄清很多,除了暗示既不需要排水也不需要关闭。因此,下面描述的上下文的解决方案在我看来很干净,它终止了worker并删除了对它们或有问题的通道的所有引用,因此,让GC清理通道及其内容:
字符串