Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Goroutine does not execute if time.Sleep included

The following code runs perfectly fine:

package main

import (
    "fmt"
)

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

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

    c<-3
}

playgound_1

However if I change

c<-3

to

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

playground_2

My code does not execute.

My gut feeling is that somehow main returns before the my_func finishes executing, but it seems like adding a pause should not have any effect. I am totally lost on this simple example, what's going on here?

like image 502
Akavall Avatar asked Feb 03 '15 20:02

Akavall


People also ask

Is time sleep blocking in Golang?

So no, time. Sleep does not block the goroutine.

How does time sleep work in Golang?

In Go language, time packages supplies functionality for determining as well as viewing time. The Sleep() function in Go language is used to stop the latest go-routine for at least the stated duration d. And a negative or zero duration of sleep will cause this method to return instantly.

How do you stop a Goroutine from running?

You can't kill a goroutine from outside. You can signal a goroutine to stop using a channel, but there's no handle on goroutines to do any sort of meta management. Goroutines are intended to cooperatively solve problems, so killing one that is misbehaving would almost never be an adequate response.

How do you know if a Goroutine is running?

The best way is not to know if it's till alive but to know when it dies so you can restart it. You can do that by setting a defer with a recover on your goroutine which would write to a channel signaling the death of the goroutine.


1 Answers

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.

like image 123
icza Avatar answered Oct 31 '22 02:10

icza