以下代码运行完全正常:
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
}
但是,如果我改变
c<-3
到
time.Sleep(time.Second)
c<-3
我的代码没有执行。
我的直觉是,main
在my_func
完成执行之前会以某种方式{{1}}返回,但似乎添加暂停应该没有任何效果。我完全迷失在这个简单的例子上,这里发生了什么?
答案 0 :(得分:12)
当main
函数结束时,程序以此结束。它不会等待其他goroutines完成。
引用Go Language Specification: Program Execution:
程序执行从初始化主包然后调用函数
main
开始。当该函数调用返回时,程序退出。它不会等待其他(非main
)goroutines完成。
因此,当您的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将从c
发送的频道main()
中获得值。但是一旦收到值,main
函数可能继续,但由于发送后没有更多的语句,它只是结束 - 与程序一起。非main
goroutine是否时间或偶然使用fmt.Println()
打印未定义。< / p>