This question have quite possibly been answered by I couldn't find it so here we go:
I have this go function that sends or recieves "messages", whichever one is avaivable, using a select statement:
func Seek(name string, match chan string) {
select {
case peer := <-match:
fmt.Printf("%s sent a message to %s.\n", peer, name)
case match <- name:
// Wait for someone to receive my message.
I start this function on 4 different go-routines, using an unbuffered channel (It would be better to use a buffer och 1 but this is merely experimental):
people := []string{"Anna", "Bob", "Cody", "Dave"}
match := make(chan string)
for _, name := range people {
go Seek(name, match, wg)
Now, I've just started using go and thought that since we're using an unbuffered channel, both the send and recieve statement of the "select" should block (there's no one waiting to send a message so you can't recieve, and there's no one waiting to recieve so you can't send), meaning that there won't be any communcation done between the functions, aka Deadlock. However running the code shows us that this is not the case:
API server listening at: 127.0.0.1:48731
Dave sent a message to Cody.
Anna sent a message to Bob.
Process exiting with code: 0
My question to you lovely people is why this happens? Does the compiler realize that the functions want to read / write in the same channel and arranges that to happen? Or does the "select" statement continually check if there's anyone available to use the channel with?
Sorry if the question is hard to answer, I'm still a novice and not that experienced in how things operate behind the scene :)
Now, I've just started using go and thought that since we're using an unbuffered channel, both the send and recieve statement of the "select" should block (there's no one waiting to send a message so you can't recieve, and there's no one waiting to recieve so you can't send)
This is actually not true; in fact, there are multiple goroutines waiting to receive and multiple goroutines waiting to send. When a goroutine does a select like yours:
select {
case peer := <-match:
fmt.Printf("%s sent a message to %s.\n", peer, name)
case match <- name:
// Wait for someone to receive my message.
It is simultaneously waiting to send and to receive. Since you have multiple routines doing this, every routine will find both senders and receievers. Nothing will block. The selects will choose cases at random since multiple cases are unblocked at the same time.
Related
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.
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've wrapped a queue to implement the Writer and Reader interfaces (for pushing and popping, respectively).
I need to continuously listen to the queue, and handle every message that comes through. This is simple when the queue is represented as a channel, but more difficult otherwise:
loop:
for {
var data []byte
select {
case <-done:
break loop
case _, err := queue.Read(data):
fmt.Println(string(data))
}
}
What's the proper way to do this? Read here is blocking - it waits until the queue has a message.
Is there a better, more idiomatic way to achieve this?
It’s harder to take a synchronous API (like queue.Read as you described above) and make it asynchronous than it is to do the opposite.
The idea would be to create a new goroutine (using, for example go func() {...}) and have that goroutine execute the read and write the output to a channel.
Then the first goroutine would block on that channel and the one it’s already blocking on.
This has the potentially to leave orphaned resources for a little while if the read takes to long but if you have a synchronous API, it’s the best you can do.
func main() {
messages := make(chan string)
go func() { messages <- "hello" }()
go func() { messages <- "ping" }()
msg := <-messages
msg2 := <-messages
fmt.Println(msg)
fmt.Println(msg2)
The above code consistently prints "ping" and then "hello" on my terminal.
I am confused about the order in which this prints, so I was wondering if I could get some clarification on my thinking.
I understand that unbuffered channels are blocking while waiting for both a sender and a receiver. So in the above case, when these 2 go routines are executed, there isn't, in both cases,a receiver yet. So I am guessing that both routines block until a receiver is available on the channel.
Now... I would assume that first "hello" is tried into the channel, but has to wait... at the same time, "ping" tries, but again has to wait. Then
msg := <- messages
shows up, so I would assume that at that stage, the program will arbitrarily pick one of the waiting goroutines and allow it to send its message over into the channel, since msg is ready to receive.
However, it seems that no matter how many times I run the program, it always is msg that gets assigned "ping" and msg2 that gets assigned "hello", which gives the impression that "ping" always gets priority to send first (to msg). Why is that?
It’s not about order of reading a channel but about order of goroutines execution which is not guaranteed.
Try to ‘Println’ from the function where you are writing to the channel (before and after writing) and I think it should be in same order as reading from the channel.
In Golang Spec Channels order is described as:-
Channels act as first-in-first-out queues. For example, if one
goroutine sends values on a channel and a second goroutine receives
them, the values are received in the order sent.
It will prints which value is available first to be received on other end.
If you wants to synchronize them use different channels or add wait Groups.
package main
import (
"fmt"
)
func main() {
messages1 := make(chan string)
messages2 := make(chan string)
go func(<-chan string) {
messages2 <- "ping"
}(messages2)
go func(<-chan string) {
messages1 <- "hello"
}(messages1)
fmt.Println(<-messages1)
fmt.Println(<-messages2)
}
If you see you can easily receive any value you want according to your choice using different channels.
Go playground
I just went through this same thing. See my post here: Golang channels, order of execution
Like you, I saw a pattern that was counter-intuitive. In a place where there actually shouldn't be a pattern. Once you launch a go process, you have launched a thread of execution, and basically all bets are off at that point regarding the order that the threads will execute their steps. But if there was going to be an order, logic tells us the first one called would be executed first.
In actual fact, if you recompile that program each time, the results will vary. That's what I found when I started compiling/running it on my local computer. In order to make the results random, I had to "dirty" the file, by adding and removing a space for instance. Then the compiler would re-compile the program, and then I would get a random order of execution. But when compiled in the go sandbox, the result was always the same.
When you use the sandbox, the results are apparently cached. I couldn't get the order to change in the sandbox by using insignificant changes. The only way I got it to change was to issue a time.Sleep(1) command between the launching of the go statements. Then, the first one launched would be the first one executed every time. I still don't think I'd bet my life on that continuing to happen though because they are separate threads of execution and there are no guarantees.
The bottom line is that I was seeing a deterministic result where there should be no determinism. That's what stuck me. I was fully cleared up when I found that the results really are random in a normal environment. The sandbox is a great tool to have. But it's not a normal environment. Compile and run your code locally and you will see the varying results you would expect.
I was confused when I first met this. but now I am clear about this. the reason cause this is not about channel, but for goroutine.
As The Go Memory Model mention, there's no guaranteed to goroutine's running and exit, so when you create two goroutine, you cannot make sure that they are running in order.
So if you want printing follow FIFO rule, you can change your code like this:
func main() {
messages := make(chan string)
go func() {
messages <- "hello"
messages <- "ping"
}()
//go func() { messages <- "ping" }()
msg := <-messages
msg2 := <-messages
fmt.Println(msg)
fmt.Println(msg2)
}
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.