go - 转到股票行情示例未选择 'done'情况?

标签 go concurrency goroutine

我已将示例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/

相关文章:

concurrency - 我们应该做嵌套的 goroutines 吗?

java - 如何同步两个swt按钮的事件?

node.js - Nodejs EventLoop(带集群模块)和Golang Scheduler的比较

go - Go语言如何将字符串中的多个斜杠(///)替换为一个斜杠(/)?

go - 在启用 pkg/profile 的情况下运行时如何获取示例?

go - 处理字符串编码的库/包?

performance - 运行 Go 基准测试的正确输出

java - 遍历 Arraylist 时出现 ConcurrentModificationException(不删除)

Go routine 不接收通过 channel 发送的所有数据——玩具示例程序

multithreading - goroutine 或多线程在 golang 中不起作用