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.
Buffered channels allows to accept a limited number of values without a corresponding receiver for those values. It is possible to create a channel with a buffe. Buffered channel are blocked only when the buffer is full. Similarly receiving from a buffered channel are blocked only when the buffer will be empty.
When a channel is created with no capacity, it is called an unbuffered channel. In turn, a channel created with capacity is called a buffered channel. To understand what the synchronization behavior will be for any goroutine interacting with a channel, we need to know the type and state of the channel.
Golang provides buffered channels, which allow you to specify a fixed length of buffer capacity so one can send that number of data values at once. These channels are only blocked when the buffer is full. Likewise, the channel on the receiving end will only block when the buffer is empty.
An unbuffered channel is a channel that needs a receiver as soon as a message is emitted to the channel. To declare an unbuffered channel, you just don't declare a capacity. Here is an example: The first goroutine is blocked after sending the message foo since no receivers are yet ready.
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
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 the Channel
interface in a way that never blocks the writer.OverflowingChannel
when its buffer is fullFor the opposite behaviour (discarding the oldest element, not the newest) see
RingChannel
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With