Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement non-blocking write to an unbuffered channel?

Tags:

go

channel

From Effective Go

Receivers always block until there is data to receive. If the channel is unbuffered, the sender blocks until the receiver has received the value.

But signal.Notify relays signals to an unbuffered channel without blocking. How does this work and is it possible to do with other chan<- types ?

like image 904
Sridhar Avatar asked Feb 23 '18 17:02

Sridhar


People also ask

What is an unbuffered channel?

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.

What is the difference between a buffered channel and an unbuffered channel?

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.

Do buffered channels block?

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. Buffered channels can be created by passing an additional capacity parameter to the make( ) function which specifies the size of the buffer.

Are Go channels blocking?

When we send data into the channel using a GoRoutine, it will be blocked until the data is consumed by another GoRoutine. When we receive data from channel using a GoRoutine, it will be blocked until the data is available in the channel.


2 Answers

What it means when it says os.Notify will not block is the messages will be dropped were it to block. So while it's true that it doesn't block, it's not true that it will relay the signals if they can't be received immediately. This is done via simple select:

select {
    case channel <- message:
        // message sent
    default:
        // message dropped
}

Which is why the documentation for Notify explicitly states that you should use a buffered channel. Also note that buffered channels can also block, not just unbuffered channels; buffered channels only block if the buffer is already full.

select is covered in the tour and the spec.

like image 66
Adrian Avatar answered Nov 10 '22 07:11

Adrian


You can always avoid blocking while (probably) still guaranteeing delivery by using another goroutine:

go func() { channel <- message }()

Of course, this is just using the goroutine scheduler as a substitute buffer for your channel, which may or may not be wise.

like image 27
Jeremy Huiskamp Avatar answered Nov 10 '22 08:11

Jeremy Huiskamp