How to know a buffered channel is full

后端 未结 4 858
天命终不由人
天命终不由人 2021-01-30 02:07

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.

相关标签:
4条回答
  • 2021-01-30 02:47

    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.
      Specifically, if a value is written to an OverflowingChannel 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.

    0 讨论(0)
  • 2021-01-30 02:48

    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...

    0 讨论(0)
  • 2021-01-30 02:53

    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
    
    0 讨论(0)
  • 2021-01-30 03:06

    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

    0 讨论(0)
提交回复
热议问题