Goroutine does not execute if time.Sleep included

When the main function ends, the program ends with it. It does not wait for other goroutines to finish.

Quoting from the Go Language Specification: Program Execution:

Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

So simply when your main function succeeds by sending the value on the channel, the program might terminate immediately, before the other goroutine has the chance to print the received value to the console.

If you want to make sure the value gets printed to the console, you have to synchronize it with the event of exiting from the main function:

Example with a “done” channel (try it on Go Playground):

func my_func(c, done chan int) {
    fmt.Println(<-c)
    done <- 1
}

func main() {
    c := make(chan int)
    done := make(chan int)
    go my_func(c, done)

    time.Sleep(time.Second)
    c <- 3
    <-done
}

Since done is also an unbuffered channel, receiving from it at the end of the main function must wait the sending of a value on the done channel, which happens after the value sent on channel c has been received and printed to the console.

Explanation for the seemingly non-deterministic runs:

Goroutines may or may not be executed parallel at the same time. Synchronization ensures that certain events happen before other events. That is the only guarantee you get, and the only thing you should rely on.
2 examples of this Happens Before:

  • The go statement that starts a new goroutine happens before the goroutine’s execution begins.
  • A send on a channel happens before the corresponding receive from that channel completes.

For more details read The Go Memory Model.

Back to your example:

A receive from an unbuffered channel happens before the send on that channel completes.

So the only guarantee you get is that the goroutine that runs my_func() will receive the value from channel c sent from main(). But once the value is received, the main function may continue but since there is no more statements after the send, it simply ends – along with the program. Whether the non-main goroutine will have time or chance to print it with fmt.Println() is not defined.

Leave a Comment