Consider the following snippet of Go code:
c := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
fmt.Println("Sending test1...")
c <- "test1"
fmt.Println("Sending test2...")
c <- "test2"
fmt.Println("Done sending")
}()
go func() {
for {
select {
case n := <-c:
fmt.Println("Received:", n)
}
}
}()
Full source: http://play.golang.org/p/yY6JQzDMvn
I expect that the first goroutine will block when attempting to write "test1"
to the channel until the receive in the second goroutine. The expected output would be:
Sending test1...
Received: test1
Sending test2...
Received: test2
However, when I actually run the example, I end up with:
Sending test1...
Sending test2...
Received: test1
Received: test2
It would appear by the output that the send is not blocking as one would expect. What's going on here?
This is caused by a race condition in the two goroutines. By default, the Go runtime uses a single thread for all goroutines, so execution is serialized. Consider the following possible scenario for executing the code above:
Sleep()
callSleep()
call ends"test1"
is written to the channel, which blocks"Sending test2..."
and writes the second value to the channel which again blocks"Received: test1"
messageIn summary, the send is indeed blocking, it just doesn't appear to be due to the order of output.