Search code examples
gochannelgoroutine

Does go channel behavior change depending on how messages are sent to it?


Why do these 2 pieces of code execute differently?

  1. Running the below code returns a fatal error: all goroutines are asleep - deadlock!error.
func main() {
    ch := make(chan int)
    ch <- 1
    fmt.Println(<-ch)
}
  1. Running the below code correctly returns 2 and 3 (each on its own line).
    ch := make(chan int)
    go buffer(ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

func buffer(ch chan int) {
    ch <- 2
    ch <- 3
}

#1 executes correctly only when ch is defined as a buffered channel. Why? Why does ch in buffer() accept 2 values without complaining?


Solution

  • A send operation to an unbuffered channel will block until another goroutine reads from it. That's why the first piece of code deadlocks: when you send to the channel, there are no other goroutines reading from it.

    In the second case, you have a goroutine sending two values to the channel, and the main goroutine is reading twice from the channel concurrent with the sends. The channel is not accepting two sends, it is doing it one by one, the first send operation is unblocked by the first read, and the second send operation is unblocked by the second read.