为了账号安全,请及时绑定邮箱和手机立即绑定

Go 代码示例未选择“完成”情况?

Go 代码示例未选择“完成”情况?

Go
GCT1015 2023-07-26 19:47:53
改编为以下脚本:package mainimport (    "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.goTick at 2019-10-06 15:25:50.576798 -0700 PDT m=+0.504913907Tick at 2019-10-06 15:25:51.074993 -0700 PDT m=+1.003102855Tick at 2019-10-06 15:25:51.576418 -0700 PDT m=+1.504521538我的问题:为什么它不打印Received 'done'到终端?奇怪的是,如果我在Ticker stoppedPrintln 语句中发表评论,我也会看到Received 'done':> go run tickers.goTick at 2019-10-06 15:27:30.735163 -0700 PDT m=+0.504666656Tick at 2019-10-06 15:27:31.234076 -0700 PDT m=+1.003573649Tick at 2019-10-06 15:27:31.735342 -0700 PDT m=+1.504833296Ticker stopped.Received 'done'我记得,Goroutine 中的代码可以假设同步运行,所以我很困惑,因为我没有看到Println前一种情况下语句的效果,因为它发生在 Goroutine 返回之前。有人可以解释一下吗?去并发性协程
查看完整描述

2 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

发生时done <- true,main函数直接返回。


您可以添加另一个 time.Sleep() 来看看发生了什么。


    time.Sleep(1600 * time.Millisecond)

    // ticker.Stop()

    done <- true

    // fmt.Println("Ticker stopped.")

    time.Sleep(1600 * time.Millisecond)


查看完整回答
反对 回复 2023-07-26
?
SMILET

TA贡献1796条经验 获得超4个赞

...为什么它不将 Received 'done' 打印到终端?

它确实这样做了——或者更确切地说,它尝试了

当主 goroutine(调用mainpackage main)返回时(或者在此处未发生的各种情况下更早),Go 程序就会退出。您致电并发送后main返回。time.Sleep()truedone

同时,当值到达通道时,循环中的 goroutinefor就会被唤醒。这是在主 Goroutine 发送之后发生的,之后主 Goroutine 正在退出。truedone

如果在这个退出过程中,主协程花费的时间足够长,那么匿名协程就有时间打印Received 'done'。如果在这个退出过程中,主 Goroutine 足够快,那么匿名 Goroutine 永远不会完成,或者甚至永远不会开始,打印任何东西,你什么也看不到。(实际输出是由单个底层系统调用完成的,因此您要么获得全部输出,要么什么也得不到。)

您可以通过多种机制确保您派生的 goroutine 在主协程退出之前完成,但最简单的可能是使用,sync.WaitGroup因为它就是为此设计的。创建一个 waitgroup,将其计数器设置为 1(将 1 添加到其初始零),然后Done在退出匿名 goroutine 时调用该函数。让主协程等待它。


查看完整回答
反对 回复 2023-07-26
  • 2 回答
  • 0 关注
  • 80 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信