Golang routine with unbuffered channel - go

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.

Related

another golang channels questions on understanding how it processes

I'm walking through this blog post to understand channels and I have a question on the 2nd example. I modified it a bit in the playground to this, where I'm putting more items in the channel like this:
package main
import (
"fmt"
)
func main() {
n := 3
in := make(chan int)
out := make(chan int)
// We now supply 2 channels to the `multiplyByTwo` function
// One for sending data and one for receiving
go multiplyByTwo(in, out)
// We then send it data through the channel and wait for the result
in <- n
in <- 3
in <- 6
in <- 10
fmt.Println(<-out)
}
func multiplyByTwo(in <-chan int, out chan<- int) {
// This line is just to illustrate that there is code that is
// executed before we have to wait on the `in` channel
fmt.Println("Initializing goroutine...")
// The goroutine does not proceed until data is received on the `in` channel
num := <-in
// The rest is unchanged
result := num * 2
out <- result
}
but this throws an error:
Initializing goroutine...
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox639017164/prog.go:18 +0xe0
goroutine 6 [chan send]:
main.multiplyByTwo(0x430080, 0x4300c0)
/tmp/sandbox639017164/prog.go:34 +0xe0
created by main.main
/tmp/sandbox639017164/prog.go:14 +0xa0
my interpretation of this is that the channels should process data that comes in, so why would it throw an error if I'm just simply adding more to the channel? I'd assume that it would pass in the other numbers too and run those through the function as well.
if I run it like this without an out channel:
package main
import (
"fmt"
)
func main() {
n := 3
in := make(chan int)
//out := make(chan int)
// We now supply 2 channels to the `multiplyByTwo` function
// One for sending data and one for receiving
go multiplyByTwo(in)
// We then send it data through the channel and wait for the result
in <- n
in <- 3
in <- 6
in <- 10
}
func multiplyByTwo(in <-chan int) {
// This line is just to illustrate that there is code that is
// executed before we have to wait on the `in` channel
fmt.Println("Initializing goroutine...")
// The goroutine does not proceed until data is received on the `in` channel
num := <-in
// The rest is unchanged
result := num * 2
fmt.Println(result)
}
it process the first input into the channel but then errors out again. fatal error: all goroutines are asleep - deadlock!
The goroutine processes one value, and then terminates. You can only send the first value to your goroutine, after that, the goroutine is gone, and there's nothing listening to your channel. That's why you get deadlock, you're trying to send data to a channel where there are no listeners.
Your channels are unbuffered. That means, data exchange through the channel happens only when there is at least one listener reading from the channel, and some other goroutine writes to it. If you create buffered channels, you can keep adding to them until the buffer is full. Otherwise, for the write operation to succeed, there must be a matching read operation.
This would work:
func multiplyByTwo(in <-chan int) {
for num:=range in {
// process num
}
// If here, then channel in is closed
}
in <- n
in <- 3
in <- 6
in <- 10
close(in)
// Wait for the goroutine to finish
You can, if you like, think of a channel as a sort of mailbox (perhaps with special teleportation abilities, like a portal from the game Portal).
An unbuffered channel is a mailbox that has no room at all for any packages. For someone to mail a package (send a value), they must wait until the receiver's hand pokes out of the mailbox. They can then drop the package into the hand, which will withdraw back into the mailbox, taking the package with it. If someone else is in line, you must get in line behind the someone-else.
A buffered channel is a mailbox that can hold one or more packages. To send a package, get into the line if there is one. When you reach the head of the line, you may look at the box. If there is room for your package, you put it in and go on about your business. If not, you can wait until there is room, then put the package in and go on about your business.
So there is a general pattern to send:
Get in line if you have to.
When you reach the head of the queue, put your package in if there is room, otherwise wait for room—or, for an unbuffered channel, for someone to come to the other (receive) side and put their hand in to receive.
Meanwhile, if you want to receive from a channel, you queue up if needed, just as for sending. Once you're at the head of the line, you can take a package out of the box, or—for an unbuffered channel—wait with your hand sticking out of the other side of the box-with-no-room for someone to come along and put something in it.
Each goroutine is, in this analogy, like a person, or a Go gopher. It (or he or she or whatever pronoun you prefer) can queue up if needed, and put things into, or take them out of, one of these channels. Your program starts with one goroutine, which invokes main.
In your code, you spin off a second goroutine, which begins at multiplyByTwo. This one goroutine waits—once—for a number to show up in the channel, or in this case, for someone to be waiting to send a number since the channel is unbuffered. It then doubles the (single) number it got, prints the result, and quits / dies / gets buried, never to exist again.
Meanwhile your main waits for someone to be receiving—that would be your second goroutine—until it's ready to take the number 3 that's in n. That part succeeds. Then your main waits for another receive so that it can send the constant 3.
While your main is waiting, your other goroutine is doing its work—or maybe has finished its work—and exits. Now there is only one "person" (or gopher or whatever) in the whole system, waiting for a second person—who does not exist and will not ever be born—to come along to take the number. The underlying Go system can tell that this event won't ever happen, and that's when you get the message:
fatal error: all goroutines are asleep - deadlock!
(this also terminates the program).
Burak Serdar's answer shows how you can have your second goroutine keep reading numbers from the channel. This introduces a new problem: how do you tell the second goroutine that no more numbers are coming? The answer is that you can close the channel, with close.
If we stick with the mailbox analogy, you can think of closing the channel as putting a special sticker or label on the send side of the channel. This prevents anyone from doing any further putting-values-in. Any packages that are in the channel already are safe—they stay there until someone receives them—but no new packages can go in. On the receiver side, it's easy to tell the difference between a package and this special sticker: so when you encounter the "closed" sticker, you know no more values will ever come through. If the channel is unbuffered, you can see this sticker immediately. If it's buffered, you'll have to take out all the existing packages first, before you can see it.
In general, the sender should close the channel so that receivers know they will not get anything more from it. (In many specific cases, you can get away without closing the channel. In particular, if the goroutine running main returns from its call to main, all the other goroutines die more or less immediately.)
Note that once closed, no sender can close the channel again, so this means that if you have a single channel that you share across multiple senders, only one of them can close the channel! Making that work right is tricky, so it's more common to avoid sharing a channel across more than one writing-goroutine like this.

Why do we need to run unbuffered channels in go routine but buffered channels can work without go routine?

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.

The differences between channel buffer capacity of zero and one in golang

I have set channel buffer size to zero, like var intChannelZero = make(chan int) , when getting value from the intChannelZero will be blocked until the intChannelZero has value.
Also, I set channel buffer size to one, like var intChannelOne = make(chan int, 1), when getting value from the intChannelOne will be blocked until the intChannelOne has value.
We know the capacity of intChannelZero is zero, the capacity of intChannelOne is one, so I want to know:
When putting a value to the intChannelZero like intChannelZero <- 1, where the value be saved?
The differences between intChannelZero and intChannelOne when putting a value to them.
Who can explain it at the level of Golang Runtime Enviroment? Thanks a lot.
If the channel is unbuffered (capacity is zero), then communication succeeds only when the sender and receiver are both ready.
If the channel is buffered (capacity >= 1), then send succeeds without blocking if the channel is not full and receive succeeds without blocking if the buffer is not empty.
When putting a value to the intChannelZero like intChannelZero <- 1, where the value be saved?
The value is copied from the sender to the receiver. The value is not saved anywhere other than whatever temporary variables the implementation might use.
The differences between intChannelZero and intChannelOne when putting a value to them.
Send on intChannelZero blocks until a receiver is ready.
Send on intChannelOne blocks until space is available in the buffer.
Both unbuffered and buffered channel differences will be in terms of,
Sends to channel is blocked
Receives from channel is blocked
For unbuffered channels
Sends will be blocked if the channel already send a message and hasn't yet been received.
Receives will be blocked if no sends ever happened.
For buffered channels
Sends will be blocked if already n(channel size) sends happened and none of them received. ie entire channel size has been used by messages send but nothing was received.
Receives will be blocked if the buffer is empty ie doesn't have any unconsumed sends
Runtime errors
Receive blocked will throw the bellow error
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
Send blocked will throw the bellow error
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:

How to implement non-blocking write to an unbuffered 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 ?
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.

Why does this code generate an error?

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.

Resources