英文:
understanding go channel handling / buffer overflow
问题
我已经继承了一些代码,我仍然在试图理解它。其中核心部分如下:
for msg := range this.out {
for i, handler := range this.handlers {
select {
case handler <- msg:
default:
this.logger.Printf("Buffer overflow occurred for handler %s", this.names[i])
}
}
}
out
是一个 chan byte
类型的通道。
handlers
是一个 []chan []byte
类型的数组。
看起来这段代码是从 out
通道读取数据,并将数据写入到 handlers
数组中的处理器中,如果写入失败,则会打印出关于缓冲区溢出的警告信息。我想是这样的。
但是我需要更多细节。我对 Go 语言还不熟悉,这是我第一次处理通道。所以首先问题是,这段代码实际上是在做什么?如果是的话...我该如何防止缓冲区溢出?
英文:
I have inherited some code I am still trying to make sense of. The core of it is this:
for msg := range this.out {
for i, handler := range this.handlers {
select {
case handler <- msg:
default:
this.logger.Printf("Buffer overflow occurred for handler %s", this.names[i])
}
}
}
out is a chan byte
handlers is []chan []byte
It looks like this is reading from out and writing to a handler from the array, and the default is to complain about a buffer overflow. I think.
But I need details. I am new to go and this is my first time dealing with chan. So first question, is that actually what is happening here? And if so ... how do I prevent the buffer overflow?
答案1
得分: 2
在Go语言中,可以通过两种方式创建通道:
c := make(chan []byte)
这将创建一个用于同步发送方和接收方的通道。这意味着接收方必须等待发送方发送数据,而发送方必须等待接收方接收数据。然而,通过向通道添加缓冲区:
c := make(chan []byte, 100)
可以有效地使发送方和接收方异步化。在这种情况下,当缓冲区满时,发送方将被阻塞,当缓冲区为空时,接收方将被阻塞。
现在,我不知道handler
的容量是多少,但是你应该期望以下一般工作流程:
- Go将检查
handler
中是否有空间,如果有空间,msg
将被写入通道。 - 如果没有空间,则会记录错误消息。
关于缓冲区溢出,你实际上可以采取一些措施:
首先,作为一种权宜之计,你可以增加handler
的容量,以便它可以容纳更多的消息。如果问题是间歇性的(即流量的大幅波动),这可能代表了一个实际的修复。否则,你只是将问题推迟一段时间。
其次,你可以水平扩展handler
的处理程序,以处理更多的消息,从而确保通道不会溢出。然而,这样做的问题是,你随后必须担心管理具有不同容量级别的处理程序,这将涉及到自动扩展等问题。
第三,你可以查看处理来自handler
的消息的代码,并查看是否可以重新设计以更高效地处理消息。当原始设计假设不再成立时,这种重新设计是相当常见的。
最后,你可以完全放弃使用通道作为基础设施,并将该组件替换为包含内存的基于云的发布/订阅系统。这样做的好处是,它可以让你根据需要扩展应用程序,而不必担心溢出,但它将增加额外的成本并需要基础设施更改。
英文:
In Go, channels can be created in two ways:
c := make(chan []byte)
which creates a channel that will synchronize the sender and receiver. This means that the receiver will have to wait until data is sent by the sender, and the sender will have to wait until the receiver gets that data. However, by adding a buffer to the channel:
c := make(chan []byte, 100)
you're effectively desynchronizing the sender and receiver. In this case, the sender will block when the buffer is full and the receiver will block when the buffer is empty.
Now, I don't know what the capacity on handler
is, but this is the general workflow you should expect:
- Go will check if there is space in
handler
and if there is,msg
will be written to the channel. - If there is not space then the error message will be logged.
What you actually do about buffer overflow is a little more tricky.
First, as a stopgap, you could increase the capacity on handler
so that it can hold more messages. This may represent an actual fix if the problem is intermittent (i.e. large spikes in traffic). Otherwise, all you're doing is pushing the issue off for a time.
Second, you could horizontally scale the handlers on the other end of handler
to process more messages, thereby ensuring that the channel doesn't overflow. The problem with this, however, is that you then have to worry about managing handlers at various capacity levels so then you get into auto-scaling and things like that.
Third, you could look at the code handling messages from handler
and see if this could be redesigned to handle messages more efficiently. Such redesigns are pretty common when the original design assumptions for your code no longer hold.
Finally, you could move away from using channels as infrastructure altogether and replace that component with a cloud-based pub/sub that includes memory. The advantage here is that this would allow you to scale your application as necessary without worrying about overflow but it would incur additional costs and require infrastructure changes.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论