问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/28307783/goroutine-does-not-execute-if-time-sleep-included