如果包含 time.Sleep,则 Goroutine 不会执行
Goroutine does not execute if time.Sleep included
以下代码运行良好:
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
returns 在 my_func
完成执行之前不知何故,但似乎添加暂停应该没有任何效果。我完全迷失在这个简单的例子中,这是怎么回事?
当main
函数结束时,程序也随之结束。它不会等待其他 goroutines 完成。
引自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.
因此,当您的 main
函数通过在通道上发送值而成功时,程序可能会立即终止,然后其他 goroutine 才有机会将接收到的值打印到控制台。
如果您想确保该值被打印到控制台,您必须将它与退出 main
函数的事件同步:
带有 "done" 频道的示例(在 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 个例子:
- 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.
有关详细信息,请阅读 The Go Memory Model。
回到你的例子:
A receive from an unbuffered channel happens before the send on that channel completes.
所以你得到的唯一保证是运行 my_func()
的 goroutine 将从 main()
发送的通道 c
接收值。但是一旦接收到该值,main
函数 可能 继续,但由于在发送后没有更多的语句,它只是结束 - 与程序一起。非main
goroutine 是否有 time 或 chance 用 fmt.Println()
打印它是 未定义.
以下代码运行良好:
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
returns 在 my_func
完成执行之前不知何故,但似乎添加暂停应该没有任何效果。我完全迷失在这个简单的例子中,这是怎么回事?
当main
函数结束时,程序也随之结束。它不会等待其他 goroutines 完成。
引自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.
因此,当您的 main
函数通过在通道上发送值而成功时,程序可能会立即终止,然后其他 goroutine 才有机会将接收到的值打印到控制台。
如果您想确保该值被打印到控制台,您必须将它与退出 main
函数的事件同步:
带有 "done" 频道的示例(在 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 个例子:
- 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.
有关详细信息,请阅读 The Go Memory Model。
回到你的例子:
A receive from an unbuffered channel happens before the send on that channel completes.
所以你得到的唯一保证是运行 my_func()
的 goroutine 将从 main()
发送的通道 c
接收值。但是一旦接收到该值,main
函数 可能 继续,但由于在发送后没有更多的语句,它只是结束 - 与程序一起。非main
goroutine 是否有 time 或 chance 用 fmt.Println()
打印它是 未定义.