I'm trying to understand channels in Go. Here is a code example:
package main
import "fmt"
func main() {
m := make(map[int]string)
m[2] = "First Value"
c := make(chan bool)
go func() {
m[2] = "Second Value"
c <- true
}()
fmt.Printf("1-%s
", m[2])
fmt.Printf("2-%s
", m[2])
_ = <-c
fmt.Printf("3-%s
", m[2])
fmt.Printf("4-%s
", m[2])
}
Sometimes the output of the above code was (result 1):
1-First Value
2-First Value
3-Second Value
4-Second Value
but sometimes I got (result 2):
1-First Value
2-Second Value
3-Second Value
4-Second Value
After changing c := make(chan bool)
to c := make(chan bool, 1)
, the same occurred: sometimes result 1, sometimes result 2.
Why?
Your results makes perfect sense. As go routine run independent of each other, you would never know when go routine will start executing. As soon as line
m[2] = "Second Value"
is executed it will be reflected on your main go routine.
Hence when above line is executed between first and second print of your program you see result as
1-First Value
2-Second Value
3-Second Value
4-Second Value
When it is not you see other one. Before third print you ensure that other go routine is finished.
Just to clear it even more if you modify your program a little bit like
package main
import "fmt"
import "time"
func main() {
m := make(map[int]string)
m[2] = "First Value"
c := make(chan bool)
go func() {
m[2] = "Second Value"
c <- true
}()
time.Sleep(time.Second)
fmt.Printf("1-%s
", m[2])
fmt.Printf("2-%s
", m[2])
_ = <-c
fmt.Printf("3-%s
", m[2])
fmt.Printf("4-%s
", m[2])
}
You will most probably get the following output
1-Second Value
2-Second Value
3-Second Value
4-Second Value
Hope it helps.
You code actually only makes sure that the third and the forth prints display the second value. When you change the channel to have a buffer of 1 it doesn't really change anything.
So let's look at the first case. You have an unbuffered channel. The go routine you fire off changes the content of the map. But you have no idea when the scheduler will run it. That is why sometimes you see one result and an other time the other result. The call: _ = <-c
will ensure that the go routine has ran. Because this call will block until the go routine actually wrote something on the channel. That's why you will never see 'First value' in the last 2 prints.
When you use a buffered channel the only thing that will change is that the go routine will immediately exit after writing to the channel. Nothing else (read it on Effective Go).