英文:
How to know a buffered channel is full
问题
如何判断缓冲通道是否已满?当缓冲通道已满时,我不想被阻塞,而是选择丢弃发送到缓冲通道的项目。
英文:
How to know a buffered channel is full? I don't know to be blocked when the buffered channel is full, instead I choose to drop the item sent to the buffered channel.
答案1
得分: 188
你可以使用带有默认情况的select语句
。如果无法执行任何一个case,比如向一个满的通道发送数据,该语句将执行默认情况:
package main
import "fmt"
func main() {
ch := make(chan int, 1)
// 填满通道
ch <- 1
select {
case ch <- 2: // 除非通道已满,否则将2放入通道
default:
fmt.Println("通道已满。丢弃值")
}
}
输出:
通道已满。丢弃值
Playground: http://play.golang.org/p/1QOLbj2Kz2
无需发送进行检查
根据Go规范中所述,还可以使用len(ch)
来检查通道中排队的元素数量。结合cap
,我们可以在不发送任何数据的情况下检查通道是否已满。
if len(ch) == cap(ch) {
// 通道已满,但现在可能不满
} else {
// 通道未满,但现在可能满了
}
请注意,比较的结果可能在进入if
块之前就已经失效了。
英文:
You can use the select
statement with a default. In case it is not possible to do any of the cases, like sending to a full channel, the statement will do the default:
package main
import "fmt"
func main() {
ch := make(chan int, 1)
// Fill it up
ch <- 1
select {
case ch <- 2: // Put 2 in the channel unless it is full
default:
fmt.Println("Channel full. Discarding value")
}
}
Output:
>Channel full. Discarding value
Playground: http://play.golang.org/p/1QOLbj2Kz2
Check without sending
It is also possible to check the number of elements queued in a channel by using len(ch)
, as stated in the Go specifications.
This in combination with cap
allows us to check if a channel is full without sending any data.
if len(ch) == cap(ch) {
// Channel was full, but might not be by now
} else {
// Channel wasn't full, but might be by now
}
Note that the result of the comparison may be invalid by the time you enter the if
block
答案2
得分: 16
> 而我选择放弃发送到缓冲通道的项目。
这被称为"溢出通道",你可以在eapache/channels/overflowing_channel.go
中找到ANisus的答案实现:
for elem := range ch.input {
// 如果无法立即写入,就放弃并继续下一个
select {
case ch.output <- elem:
default:
}
}
close(ch.output)
但是该项目eapache/channels还实现了其他策略:
OverflowingChannel
以一种不阻塞写入者的方式实现了Channel
接口。
具体来说,如果在OverflowingChannel
的缓冲区已满时(或者在无缓冲的情况下,接收者未准备好时)写入一个值,那么该值将被简单地丢弃。
> 要实现相反的行为(丢弃最旧的元素而不是最新的元素),请参见RingChannel
。
英文:
> instead I choose to drop the item sent to the buffered channel.
That is called "overflowing channel", and you find ANisus's answer implemented in eapache/channels/overflowing_channel.go
:
for elem := range ch.input {
// if we can't write it immediately, drop it and move on
select {
case ch.output <- elem:
default:
}
}
close(ch.output)
But that project eapache/channels implements other strategies as well:
OverflowingChannel
implements theChannel
interface in a way that never blocks the writer.
Specifically, if a value is written to anOverflowingChannel
when its buffer is full
(or, in an unbuffered case, when the recipient is not ready) then that value is simply discarded.
> For the opposite behaviour (discarding the oldest element, not the newest) see RingChannel
.
答案3
得分: 5
引用来源:
这个想法很简单:通过一个Goroutine将两个缓冲通道连接起来,将消息从输入通道转发到输出通道。每当无法将新消息放入输出通道时,从输出通道中取出一条消息(即缓冲区中最旧的消息),丢弃它,并将新消息放入刚刚释放的输出通道中。
还可以查看这个C版本...
英文:
Another useful example I stumbled upon was this nifty implementation of Ring Buffer.
The quote from the source:
> The idea is simple: Connect two buffered channels through one
> Goroutine that forwards messages from the incoming channel to the
> outgoing channel. Whenever a new message can not be placed on on the
> outgoing channel, take one message out of the outgoing channel (that
> is the oldest message in the buffer), drop it, and place the new
> message in the newly freed up outgoing channel.
Check out this C version as well...
答案4
得分: 2
我使用这段代码来在通道满时移除一个元素。对于只有一个发送例程的通道,确保发送到 ch
后仍然有效。
// 如果通道满了,则从通道中移除一个元素
if len(ch) == cap(ch) {
// 通道满了,但现在可能不满了
select {
case _ := <-ch:
// 丢弃一个元素
default:
// 可能它已经是空的了
}
}
// 现在我们可以发送到通道了
这段代码的作用是,如果通道已满,则从通道中移除一个元素,以确保后续可以成功发送到该通道。
英文:
I use this code to remove one item if the channel was full. For channels with only one sending go routine it's enough to ensure that sending to ch
will work afterwards.
// Remove one item from chan if full
if len(ch) == cap(ch) {
// Channel was full, but might not be by now
select {
case _ := <-ch:
// Discard one item
default:
// Maybe it was empty already
}
}
// Now we can send to channel
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论