How to know a buffered channel is full
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 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
.