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 ?
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.
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.
Which is why the documentation for Notify explicitly states that you should use a buffered channel
With Go 1.17, the tool vet will also make that clearer:
New warning for calling signal.Notify on unbuffered channels
The vet tool now warns about calls to signal.Notify with incoming signals being sent to an unbuffered channel.
Using an unbuffered channel risks missing signals sent on them as signal.Notify does not block when sending to a channel.
For example:
c := make(chan os.Signal)
// signals are sent on c before the channel is read from.
// This signal may be dropped as c is unbuffered.
signal.Notify(c, os.Interrupt)
Users of signal.Notify should use channels with sufficient buffer space to keep up with the expected signal rate.
So, this doesn't answer directly to the problem since it asks for a unbuffered channel, but if all you want is for it not to block on send, this is what I came up with:
ch := make(chan shared.BlogPost, 1024)
You just put a number larger than expected. If you don't know in advance the maximum capacity, then this solution might not work for you.
Also remember that go allocates the channel eagerly, so be careful with memory usage.
Related
I was going through tutorials on gobyexample. I noticed the author has shown example of gochannel using go routine but in buggered go channel he is directly sending messages to channel .
I tried on my local system to run unbuffered channel without go routine but it is throwing "fatal error: all goroutines are asleep - deadlock!"
but buffered channels are working fine without go routine
func channelDemo() {
message := make(chan string)
// go func() {
// message <- "Hello"
// }()
message <- "Hello"
msg := <-message
fmt.Println("msg", msg)
}
func channelBufferingDemo() {
messages := make(chan string, 3)
messages <- "Buffered"
messages <- "channel"
fmt.Println(<-messages)
fmt.Println(<-messages)
}
A channel send will succeed only if the channel can accept the input, that is, either there's a listener for that channel, or there is available buffer in the channel. Otherwise goroutine will go to sleep until one of those become true: either someone starts listening, or someone reads from the channel and there is now buffer space.
With a channel with no buffer, the only way you can write to it is if someone is listening to it. If there is only one goroutine and if you write to the channel, all goroutines will be asleep.
With a channel with buffer size 3 and one goroutine, you can write to if 3 times without reading from it. The 4th write will put all goroutines to sleep.
buffered channels are working fine without go routine
because they won't block until their buffer is full.
Which is what happens in channelBufferingDemo. It has a length of 3, you write twice on it, it is not full, thus the program keeps going on, you read twice on it, it dequeues and let the program finish.
In channelDemo the channel does not have a buffer, so the first time you read or write, it blocks until another routine performs the opposite operations.
Because in your example you are running both operations sequentially within the same routine, it inevitably block, ending with this fatal error.
I am reading the book Go in action.
This is how the unbuffered channel are described:
An unbuffered channel is a channel with no capacity to hold any value
before it’s received. These types of channels require both a sending
and receiving goroutine to be ready at the same instant before any
send or receive operation can complete. If the two goroutines aren’t
ready at the same instant, the channel makes the goroutine that
performs its respective send or receive operation first wait.
Synchronization is inherent in the interaction between the send and
receive on the channel. One can’t happenwithout the other.
The book use the following figure to illustrate the unbuffered channel:
So I just wonder how about if there are three or more goroutine which share the same channel?
For example, three goroutine GA GB GC share the same channel c
Now once GA send message through c, how do we make sure that both GB and GC will receive the message? Since as the book said:
These types of channels require both a sending and receiving goroutine
to be ready at the same instant
Which means when two goroutine are exchanging the message, the third must lost the message.
Is this the right way goroutine run?
A message sent through a channel is delivered to exactly one receiving goroutine.
Assuming you have three goroutines, one sending and two receiving, the sending goroutine needs to send two messages for both the receiving goroutines to unblock, like this:
var c = make(chan int)
go func() { fmt.Printf("got %d\n", <-c) }()
go func() { fmt.Printf("got %d\n", <-c) }()
c <- 1
c <- 2
Also notice that this also requires the receiving goroutines to read exactly one message each. If they were to do it in a loop, one of them might receive both messages and the other none.
If there are 2 or many receivers and one sender on a channel(buffered/unbuffered) and sender sends a message through the channel, only one out of all the receivers will get the message.
Let say goroutine A and B are reading from unbuffered channel c. They are both blocked as the channel is unbuffered.
Goroutine D write something into channel. One of A or B will receive data and will be unblocked the other one stay blocked until D or other goroutine write another thing into channel.
You are right, only one receiver can get one specific message from a channel (buffered or unbuffered). If you want multiple receivers to read all messages from a channel, you will have to put a multiplexer between the original channel and the receivers, which would read the messages and forward them to N channels, one for each receiver.
If we would draw it out it would look something like this (GA is the sender, GB, GC, GZ are receivers, c, cB, cC, cZ are channels and multiplexer is self explanatory).
+-> [cB] -> GB
|
GA -> [c] -> multiplexer +-> [cC] -> GC
|
...
|
+-> [cZ] -> GZ
You can also look at this answer for a code example.
I try to explore go channel, i create channel buffer max 10, with gomaxprocess is 2, but i wonder why this code won't receive message
runtime.GOMAXPROCS(2)
messages := make(chan int, 9)
go func() {
for {
i := <-messages
fmt.Println("Receive data:", i)
}
}()
for i := 0; i <= 9; i++ {
fmt.Println("Send data ", i)
messages <- i
}
Your case works like this, though it may appear to work certain times, but it's not guaranteed to always.
Just to add some context, in an unbuffered channel, the sending go routine is blocked as it tries to send a value and a receive is guaranteed to occur before the sending go routine is awakened (in this case the main), so it may seem like a viable option in such cases. But the sending go routine may still exit before the print statement in the receiving go routine is executed. So basically you need to use a synchronization mechanism such that the sending go routine exits only after the work in the receiver is completed.
Here's how you can use a synchronization mechanism, have annotated it so that you can make better sense out of it. This will work for both buffered and unbuffered channels. Another option is to have the receive in the main thread itself so that it doesn't exit before receive processing is done, this way you won't need a separate synchronization mechanism. Hope this helps.
You created a channel which has 9 buffer space, which means main routine (r1) will not blocked until the 10th element was ready to send to messages.
In your go func() (r2), it most probably starts running when r1 almost finished for r2 is a new routine and system takes time to create stacks etc.
so, r2 doesn't print anything, for r1 is done and program exits while r2 has just begin running.
The below piece of code generates an error why?
func main() {
messages := make(chan string)
messages <- "test" //line 16
fmt.Println(<-messages)
}
Generates the below error.
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox994400718/main.go:16 +0x80
A value is sent to the channel, and in the next line it's being received. Technically it should work.
Channels can be buffered or unbuffered. A buffered channel can store a number of items “inside” it, but when you add something to a buffered channel the goroutine adding the item can only continue when another goroutine removes the item. There is no place to “leave” the item, it must be passed directly to the other goroutine, and the first goroutine will wait until another one take the item from it.
This is what is happening in your code. When you create a channel with make, if you don’t specify a capacity as the second argument you get an unbuffered channel. To create a buffered channel pass a second argument to make, e.g.
messages := make(chan string, 1) // could be larger than 1 if you want
This allows the goroutine to add the item (a string in this case) to the channel, where it will be available when another goroutine tries to get an item from the channel in the future, and the original goroutine can then continue processing.
I have learnt a lot about channels now, and now I'm able to answer the question.
In line 16 when the message "test" is sent to the channel by the main thread(goroutine) the execution pauses and the runtime looks for other goroutines which are ready to receive the value from the channel message. Since there are no other channels the runtime raises a panic with the deadlock message. This a classic example for deadlock.
To fix this there are two things that can be done.
1) Use buffered channels as Matt suggested(one of the answers).
2) Else have the statement that sends to channel or receives from channel in a go routine.
func main() {
messages := make(chan string)
go func() {
messages <- "test" //line 16
}()
fmt.Println(<-messages)
}
So the essential take aways from this is that,
1) Channels can be used only to communicate between goroutines i.e when you send to channel in one goroutine you can receive it only in another goroutine not the same.
2) When data is sent to a channel in a goroutine the flow/execution of that goroutine is paused until the data is received from the same channel in another goroutine.
I'm learning Go and so far very impressed with it. I've read all the online docs at golang.org and am halfway through Chrisnall's "The Go Programming Language Phrasebook". I get the concept of channels and think that they will be extremely useful. However, I must have missed something important along the way, as I can't see the point to one-way channels.
If I'm interpreting them correctly, a read-only channel can only be received on and a write-only channel can only be transmitted on, so why have a channel that you can send to and never receive on? Can they be cast from one "direction" to the other? If so, again, what's the point if there's no actual constraint? Are they nothing more than a hint to client code of the channel's purpose?
A channel can be made read-only to whoever receives it, while the sender still has a two-way channel to which they can write. For example:
func F() <-chan int {
// Create a regular, two-way channel.
c := make(chan int)
go func() {
defer close(c)
// Do stuff
c <- 123
}()
// Returning it, implicitly converts it to read-only,
// as per the function return type.
return c
}
Whoever calls F(), receives a channel from which they can only read.
This is mostly useful to avoid potential misuse of a channel at compile time.
Because read/write-only channels are distinct types, the compiler can use
its existing type-checking mechanisms to ensure the caller does not try to write
stuff into a channel it has no business writing to.
I think the main motivation for read-only channels is to prevent corruption and panics of the channel. Imagine if you could write to the channel returned by time.After. This could mess up a lot of code.
Also, panics can occur if you:
close a channel more than once
write to a closed channel
These operations are compile-time errors for read-only channels, but they can cause nasty race conditions when multiple go-routines can write/close a channel.
One way of getting around this is to never close channels and let them be garbage collected. However, close is not just for cleanup, but it actually has use when the channel is ranged over:
func consumeAll(c <-chan bool) {
for b := range c {
...
}
}
If the channel is never closed, this loop will never end. If multiple go-routines are writing to a channel, then there's a lot of book-keeping that has to go on with deciding which one will close the channel.
Since you cannot close a read-only channel, this makes it easier to write correct code. As #jimt pointed out in his comment, you cannot convert a read-only channel to a writeable channel, so you're guaranteed that only parts of the code with access to the writable version of a channel can close/write to it.
Edit:
As for having multiple readers, this is completely fine, as long as you account for it. This is especially useful when used in a producer/consumer model. For example, say you have a TCP server that just accepts connections and writes them to a queue for worker threads:
func produce(l *net.TCPListener, c chan<- net.Conn) {
for {
conn, _ := l.Accept()
c<-conn
}
}
func consume(c <-chan net.Conn) {
for conn := range c {
// do something with conn
}
}
func main() {
c := make(chan net.Conn, 10)
for i := 0; i < 10; i++ {
go consume(c)
}
addr := net.TCPAddr{net.ParseIP("127.0.0.1"), 3000}
l, _ := net.ListenTCP("tcp", &addr)
produce(l, c)
}
Likely your connection handling will take longer than accepting a new connection, so you want to have lots of consumers with a single producer. Multiple producers is more difficult (because you need to coordinate who closes the channel) but you can add some kind of a semaphore-style channel to the channel send.
Go channels are modelled on Hoare's Communicating Sequential Processes, a process algebra for concurrency that is oriented around event flows between communicating actors (small 'a'). As such, channels have a direction because they have a send end and a receive end, i.e. a producer of events and a consumer of events. A similar model is used in Occam and Limbo also.
This is important - it would be hard to reason about deadlock issues if a channel-end could arbitrarily be re-used as both sender and receiver at different times.