我已将示例https://gobyexample.com/tickers修改为以下脚本:
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(500 * time.Millisecond)
done := make(chan bool)
go func() {
for {
select {
case <-done:
fmt.Println("Received 'done'")
return
case t := <-ticker.C:
fmt.Println("Tick at", t)
}
}
}()
time.Sleep(1600 * time.Millisecond)
// ticker.Stop()
done <- true
// fmt.Println("Ticker stopped.")
}
与引用的示例的两个区别是,我已注释掉
ticker.Stop()
行,并在fmt.Println("Received 'done'")
块中添加了case <-done
行。如果运行此命令,则会观察到以下输出:> go run tickers.go
Tick at 2019-10-06 15:25:50.576798 -0700 PDT m=+0.504913907
Tick at 2019-10-06 15:25:51.074993 -0700 PDT m=+1.003102855
Tick at 2019-10-06 15:25:51.576418 -0700 PDT m=+1.504521538
我的问题:为什么不将
Received 'done'
打印到终端?奇怪的是,如果我在
Ticker stopped
Println语句中发表评论,我也会看到Received 'done'
:> go run tickers.go
Tick at 2019-10-06 15:27:30.735163 -0700 PDT m=+0.504666656
Tick at 2019-10-06 15:27:31.234076 -0700 PDT m=+1.003573649
Tick at 2019-10-06 15:27:31.735342 -0700 PDT m=+1.504833296
Ticker stopped.
Received 'done'
我记得,可以假定Goroutine中的代码是同步运行的,所以我感到困惑的是,在前一种情况下,我看不到
Println
语句的影响,因为它发生在Goroutine返回之前。有人可以解释吗?
最佳答案
... why does it not print Received 'done' to the terminal?
它确实可以,或者,它会尝试。
当主goroutine(称为
main
包的main
)返回(或更早在各种情况下未在此处发生)时,Go程序退出。调用main
然后在time.Sleep()
上发送true
后,您的done
返回。同时,当
for
值到达true
channel 时,位于done
循环中的goroutine会唤醒。这在主goroutine发送完之后发生,此后主goroutine正在退出过程中。如果在退出过程中主goroutine花费了足够长的时间,则匿名goroutine将有时间打印
Received 'done'
。如果在退出过程中主goroutine足够快,则匿名goroutine永远不会完成,甚至可能永远不会开始,打印任何内容,而您什么也看不到。 (实际输出是通过单个基础系统调用完成的,因此您可以全部获得,也可以全部不获得。)您可以通过多种方法确保在退出主程序之前就完成了goroutine,但是最简单的方法可能是使用
sync.WaitGroup
,因为它是为此目的而设计的。创建一个 WaitGroup ,将其计数器设置为1(向其初始零添加1),然后在退出匿名goroutine的途中调用Done
函数。让主goroutine等待它。参见Go Playground example。
关于go - 转到股票行情示例未选择 'done'情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58261752/