当main 函数结束时,程序也随之结束。它不会等待其他 goroutine 完成。
引用Go Language Specification: Program Execution:
程序执行从初始化主包开始,然后调用函数main。当该函数调用返回时,程序退出。它不会等待其他(非main)goroutine 完成。
因此,当您的main 函数通过在通道上发送值而成功时,程序可能会立即终止,在另一个 goroutine 有机会将接收到的值打印到控制台之前。
如果要确保将值打印到控制台,则必须将其与退出 main 函数的事件同步:
以“完成”频道为例(在 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
}
由于done 也是一个无缓冲通道,因此在main 函数结束时从它接收必须等待done 通道上的值的发送,这发生在通道c 上发送的值之后已收到并打印到控制台。
对看似不确定的运行的解释:
Goroutines 可能会或可能不会并行执行同时。同步确保某些事件在其他事件之前发生。这是您获得的唯一保证,也是您唯一应该依赖的东西。
2 个例子发生在之前:
- 启动新 goroutine 的
go 语句发生在 goroutine 开始执行之前。
- 通道上的发送发生在来自该通道的相应接收完成之前。
更多详情请阅读The Go Memory Model。
回到你的例子:
来自无缓冲通道的接收发生在该通道上的发送完成之前。
所以你得到的唯一保证是运行my_func()的goroutine将接收来自main()的通道c的值。但是一旦接收到值,main 函数可能 会继续,但由于发送后没有更多的语句,它只是与程序一起结束。非main 协程是否有时间 或机会 使用fmt.Println() 打印它未定义。