Go Channel writes data beyond it's capacity - go

package main
import (
"fmt"
)
func write(ch chan int) {
for i := 0; i < 5; i++ {
fmt.Println("avaliable", i)
ch <- i
fmt.Println("successfully wrote", i, "to ch")
}
close(ch)
}
func main() {
ch := make(chan int)
go write(ch)
for v := range ch {
fmt.Println("read value", v, "from ch")
}
}
Output
avaliable 0
successfully wrote 0 to ch
avaliable 1
read value 0 from ch
read value 1 from ch
successfully wrote 1 to ch
avaliable 2
successfully wrote 2 to ch
avaliable 3
read value 2 from ch
read value 3 from ch
successfully wrote 3 to ch
avaliable 4
successfully wrote 4 to ch
read value 4 from ch
Since this is a unbuffered channel it should have blocked as soon as data is written into it until another goroutine reads from the same channel. But it accepts data beyond it's capacity.
Intended Behavior
package main
import (
"fmt"
"time"
)
func write(ch chan int) {
for i := 0; i < 5; i++ {
fmt.Println("avaliable", i)
ch <- i
fmt.Println("successfully wrote", i, "to ch")
}
close(ch)
}
func main() {
ch := make(chan int)
go write(ch)
time.Sleep(time.Second)
for v := range ch {
fmt.Println("read value", v, "from ch")
time.Sleep(time.Second)
}
}
Output
avaliable 0
read value 0 from ch
successfully wrote 0 to ch
avaliable 1
read value 1 from ch
successfully wrote 1 to ch
avaliable 2
read value 2 from ch
successfully wrote 2 to ch
avaliable 3
read value 3 from ch
successfully wrote 3 to ch
avaliable 4
read value 4 from ch
successfully wrote 4 to ch
If some timers are placed throughout the code so that the main goroutine is blocked before each iteration it works as expected.

You can't infer anything from your output, because there is no ordering guarantee between the "read value" and "successfully wrote" Printfs executing. (There is one between the "available" Printf, which occurs before the channel send, and the "read value" Printf, which occurs after the corresponding channel receive, and you can see that that ordering is never violated in your output).
The channel isn't buffering anything, because it has no buffer; it's just that the two different goroutines run in an indeterminate order after the channel send completes. Sometimes the sending side gets to go first and prints the "successfully wrote" message, and sometimes the receiving side gets to go first and prints the "read value" message. Neither one ever "gets ahead" by more than one value, because they're still fully synchronized on the channel send; they're just racing to print their status messages immediately after.
When you add the Sleep calls to main, it just so happens to make it so that the goroutine running write will always be blocked on waiting to send the next value, while the one running main blocks on the call to Sleep. When the timer expires, the main goroutine wakes up, and immediately finds that it has something waiting for it on the channel, grabs it, and goes back to sleep, and then the write goroutine gets woken up. By slowing things down you've gotten the scheduler to run things in a consistent order (although it's still partly a matter of luck); without the sleeps, with everything running as fast as it can, the result is apparently random.

If that were the case, the output of the "sleeping" version would be even more chaotic.
You cannot expect a coherent output from two independent threads even if they are synchronized at some point.

Related

How does writing/reading multiple values to/from a unbuffered channel work in Go?

This seems to challenge my understanding of unbuffered channel, which is that it can only take one value and then it would block for a reader to read it.
How in the following code writeToChan is able to write 3 values?
More so surprisingly, how are those values available to be read later albeit not in same order?
An excerpt from https://golang.org/doc/effective_go#channels
Receivers always block until there is data to receive. If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go writeToChan(ch)
go rdFrmChan(ch)
x := <- ch
fmt.Println("main read 1 -:",x)
fmt.Println("main read 2 -:",<-ch)
}
func writeToChan(c chan int) {
time.Sleep(time.Second * 1)
c <- 42
c <- 27
c <- 9
}
func rdFrmChan(c chan int) {
fmt.Println("Go routine read :", <-c)
}
Output:
Go routine read : 27
main read 1 -: 42
main read 2 -: 9
Playground link: https://play.golang.org/p/DYzfYh-kXnC
Each line of the excerpt pasted is proven by your example code, if you understand the sequence of events happening.
After the goroutines are started, your main routine is blocked reading from the channel c, as it is yet to see a value to read. The writeToChan routine waits for a second before writing the first value to the channel
The goroutine rdFrmChan is also blocked, because it is waiting to read on the channel ch
After 1s, when the sleep on writeToChan expires, the first write (c <- 42) will unblock your main routine first, causing the value to be stored in x i.e. 42
Next the rdFrmChan is unblocked on the next write to the channel (c <- 27) and sees the value 27. The routine terminates at this point after printing the value
At this point, there is only value to be written and one to be read. The third write (c <- 9) from the goroutine allows the main routine to read the value as part of <-ch and print it

Go channels seem not to be blocking although supposed to be

I am new to golang and have a hard time understanding how the channels work. My understanding is that by default, channels are supposed to be blocking, so I expect a goroutine that writes into a channel to be frozen by the scheduler until an other goroutine reads the channel content. So I tried the following code, which gives the corresponding output:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var v int
func main() {
ch := make(chan string)
wg.Add(2)
go func(ch chan string) {
fmt.Println("Ready to receive")
for msg := range ch {
fmt.Println("received: ", msg)
fmt.Println(v)
}
wg.Done()
}(ch)
go func(ch chan string) {
fmt.Println("Will send the SMS to mama")
ch <- "msg 1"
v += 1
fmt.Println("Done! sent the message 1")
ch <- "msg 2"
v += 1
fmt.Println("Done! sent the message 2")
ch <- "msg 3"
v += 1
fmt.Println("Done! sent the message 3")
close(ch)
wg.Done()
}(ch)
wg.Wait()
}
output:
Will send the SMS to mama
Ready to receive
received: msg 1
0
Done! sent the message 1
Done! sent the message 2
received: msg 2
2
received: msg 3
2
Done! sent the message 3
I am a bit surprised as I was expecting the following order:
msg 1 sent
msg 1 received
msg 2 sent
msg 2 received
and so on. But this is obviously not the case.
Does someone have any idea on why Go behaves this way? Many thanks,
Here is a link to the code https://play.golang.org/p/O6SXf0CslPf. And here are my sources for stating what I said earlier: https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adb https://rakyll.org/scheduler/
This behaviour is completely normal so to answer your question
so I expect a goroutine that writes into a channel to be frozen by the scheduler until an other goroutine reads the channel content
Schedular may or may not continue that same goroutine after value is sent through channel unless further synchronization is needed.
So for example After "msg 2" is sent to ch and is read in another goroutine in the following line
ch <- "msg 2"
goroutine can continue to execute v += 1 and call fmt.Println before other goroutine calls it.
Also calls to fmt.Println from different goroutines requires synchronization and possibly mutex calls which may also reorder print statements.
Further more there is data race on variable v

comparation about keyword "go" and without in Goroutine

The following code logged an error:
fatal error: all goroutines are asleep - deadlock!
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
But when I changed the code into this:
package main
import "fmt"
func assign (ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign (ch)
fmt.Println(<-ch)
}
"1" was printed out.
Then I used buffered channels:
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
"1" and "2" can also be printed out.
I'm a little confused about the situation. Thanks in advance!
Why the deadlock happened:
In the first code snippet you have only one main goroutine and it is blocked when you are trying to write into the channel here:
ch <- 1
Because nobody reads from the channel and the main goroutine is waiting for this to continue.
See Effective Go -> Channels
If the channel is unbuffered, the sender blocks until the receiver has received the value.
The sender is main function, the receiver is also main function.
How to avoid the deadlock:
In order to solve this, you have two options:
Option 1: make the ch channel buffered like this:
ch := make(chan int, 1) // buffer length is set to 1
From A Tour of Go
Sends to a buffered channel block only when the buffer is full.
So, you can write to the channel until the buffer is full. Then somebody has to start reading from the channel.
Option 2: write to the channel from a goroutine, like you did in the second code snippet:
func assign(ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign(ch) // does not block the main goroutine
fmt.Println(<-ch) // waiting to read from the channel
}
In this case main function will be executed until fmt.Println(<-ch) and continues as soon as it can read from the channel.
When you are using unbuffered channel, goroutine is blocked during write until someone does the read.
In your first snippet, there is an unbuffered channel and single goroutine (main goroutine).
So when you are trying to write:
ch <- 1
Nobody reads from the channel yet. The main goroutine is blocked and this line is never executed:
fmt.Println(<-ch)
That's why you've got the deadlock error.
In the second example, you still using unbuffered channel, which means write operation blocks the goroutine.
But by using go you are running the second goroutine.
It means even if this new goroutine will be blocked during write (in your assign function), the main goroutine will continue to work and fmt.Println(<-ch) will be executed and do the read (which in turn unblock background goroutine and assign function will finally reach the end).
To get more understanding about channels and goroutines, this snippet will give the same result (as your second snippet):
package main
import "fmt"
func print(ch chan int) {
fmt.Println(<-ch)
}
func main() {
ch := make(chan int)
go print(ch)
ch <- 1
}
When you are working with a buffered channel (third snippet), you can do N write operations without blocking goroutine (where N is the size of the buffer).
That's why in your example you did 2 writes without blocking and is able to read them later. But if your buffer is less than the count of write operations, and nobody do the read, you will fall into the same blocking issues (see the explanation of 1&2 snippets).

Go Channels and delays

I was just experimenting with Go channels on my Ubuntu 64 bit environment and got confused with the output the following program produced.
I got the output:
0
1
2
3
Exit
The output when I uncommented the two commented lines:
0
1
2
3
4
Exit
Please explain the behavior.
TIA.
package main
import (
"fmt"
//"time"
)
func main() {
ch := make(chan int)
done := make(chan bool)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
//time.Sleep(1 * time.Second)
done <- false
}()
go func() {
for {
select {
case message := <-ch:
fmt.Println(message)
case <-done:
return
}
}
}()
<-done
fmt.Println("Exit")
}
Your main thread is waiting on done, then exiting. Meanwhile your first go function pipes 5 values into ch, then sends to done.
The value in done then gets read from the main thread and happens to occur before the second go function reads the last value from ch. When it does so, it exits the program.
Note that if your second thread did happen to both read from ch and done, then your program would deadlock since the main thread would never receive on done and all running go threads would be blocked waiting to receive on channels.
You're not waiting for both goroutines, and only sending a single value over done to 2 receivers, which will deadlock if the second receiver happens to be main.
Using a WaitGroup simplifies the code, and allows you to easily wait for as many goroutines as needed. https://play.golang.org/p/MWknv_9AFKp
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
defer close(ch)
for i := 0; i < 5; i++ {
ch <- i
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for message := range ch {
fmt.Println(message)
}
}()
wg.Wait()
fmt.Println("Exit")
You have two go routines running in parallel. One inserts 5 numbers into the channel and then signals the main thread to exit, and another one reads the numbers from the channel.
Note that once the go routine that is responsible for enqueuing the numbers into the channel finishes, it signals the main thread to exit, regardless of whether the go routine that reads the numbers finished or not. So you could end up with a case where the enqueueing go routine finished before the dequeuing finished, and the main thread exited.
By adding the sleep, you make the enqueueing go routine live a bit longer and give a chance to the dequeueing go routine to read and print all the numbers before the enqueueing go routine signals the main thread to exit.
To solve that, you could just run the dequeuing code in the main thread. No need to run it in a go routine in this case.

How does make(chan bool) behave differently from make(chan bool, 1)?

My question arises from trying to read a channel, if I can, or write it, if I can, using a select statement.
I know that channels specified like make(chan bool, 1) are buffered, and part of my question is what is the difference between that, and make(chan bool) -- which this page says is the same thing as make(chan bool, 0) --- what is the point of a channel that can fit 0 values in it?
See playground A:
chanFoo := make(chan bool)
for i := 0; i < 5; i++ {
select {
case <-chanFoo:
fmt.Println("Read")
case chanFoo <- true:
fmt.Println("Write")
default:
fmt.Println("Neither")
}
}
A output:
Neither
Neither
Neither
Neither
Neither
(Removing the default case results in a deadlock!!)
Now see playground B:
chanFoo := make(chan bool, 1) // the only difference is the buffer size of 1
for i := 0; i < 5; i++ {
select {
case <-chanFoo:
fmt.Println("Read")
case chanFoo <- true:
fmt.Println("Write")
default:
fmt.Println("Neither")
}
}
B output:
Write
Read
Write
Read
Write
In my case, B output is what I want. What good are unbuffered channels? All the examples I see on golang.org appear to use them to send one signal/value at a time (which is all I need) -- but as in playground A, the channel never gets read or written. What am I missing here in my understanding of channels?
what is the point of a channel that can fit 0 values in it
First I want to point out that the second parameter here means buffer size, so that is simply a channel without buffers (un-buffered channel).
Actually that's the reason why your problem is generated. Un-buffered channels are only writable when there's someone blocking to read from it, which means you shall have some coroutines to work with -- instead of this single one.
Also see The Go Memory Model:
A receive from an unbuffered channel happens before the send on that channel completes.
An unbuffered channel means that read and writes from and to the channel are blocking.
In a select statement:
the read would work if some other goroutine was currently blocked in writing to the channel
the write would work if some other goroutine was currently blocked in reading to the channel
otherwise the default case is executed, which happens in your case A.
Unbuffered channels (created without capacity) will block the sender until somebody can read from them, so to make it work as you expect, you should use two goroutines to avoid the deadlock in the same thread.
For example, with this code: http://play.golang.org/p/KWJ1gbdSqf
It also includes a mechanism for the main func to detect when both goroutines have finished.
package main
import "fmt"
func send(out, finish chan bool) {
for i := 0; i < 5; i++ {
out <- true
fmt.Println("Write")
}
finish <- true
close(out)
}
func recv(in, finish chan bool) {
for _ = range in {
fmt.Println("Read")
}
finish <- true
}
func main() {
chanFoo := make(chan bool)
chanfinish := make(chan bool)
go send(chanFoo, chanfinish)
go recv(chanFoo, chanfinish)
<-chanfinish
<-chanfinish
}
It won't show the alternate Read and Write, because as soon as send writes to the channel, it is blocked, before it can print the "Write", so the execution moves to recv that receives the channel and prints "Read". It will try to read the channel again but it will be blocked and the execution moves to send. Now send can write the first "Write", send to the channel (without blocking because now there is a receiver ready) and write the second "Write". In any case, this is not deterministic and the scheduler may move the execution at any point to any other running goroutine (at least in the latest 1.2 release).

Resources