go select case 问题?

    ticker1 := time.NewTicker(3 * time.Second)
    ticker2 := time.NewTicker(3 * time.Second)
    fmt.Println("当前时间为:", time.Now())
    go func() {
        for {
            select {
            case <-ticker1.C:
                t := <-ticker1.C
                fmt.Println("当前时间为=1=:", t)
            }
        }
    }()
    go func() {
        for {

            //从定时器中获取数据
            t := <-ticker2.C
            fmt.Println("当前时间为=2=:", t)

        }
    }()

如代码所示
目的都是像间隔3s执行一次
但是实际执行的时候 1 执行一次要比 2 间隔更久
image.png
因为最近在弄一个线上项目 这个周期本来是设定10s的最后变成了 一分多钟才执行一次
好奇是什么问题导致的?

阅读 996
avatarAI BotBETA

这个问题可能是由于 Go 语言的 select 语句的工作方式导致的。在 select 语句中,Go 语言会随机选择一个可用的 case 来执行。这意味着,如果多个 case 都准备好了,Go 语言会随机选择一个执行,而不是按照顺序或者其他方式选择。

在你的代码中,ticker1ticker2 都是每3秒发送一次时间。但是,由于 select 语句的随机选择行为,ticker1 可能在 ticker2 之前或者之后被执行。如果 ticker1 先被执行,那么它将会阻塞 select 语句,直到3秒后再次执行。而在这3秒内,ticker2 可能已经执行了多次。

解决这个问题的一个方式是使用 time.Tick 方法代替 select 语句。time.Tick 方法会定期返回一个通道,这个通道会在每次调用 time.Tick 时被填充一个新的时间。这样,你可以在两个定时器之间同步时间,而不是依赖 select 语句的随机选择行为。

下面是一个使用 time.Tick 的例子:

ticker1 := time.NewTicker(3 * time.Second)
ticker2 := time.NewTicker(3 * time.Second)
fmt.Println("当前时间为:", time.Now())
go func() {
    for t := range ticker1.C {
        fmt.Println("当前时间为=1=:", t)
    }
}()
go func() {
    for t := range ticker2.C {
        fmt.Println("当前时间为=2=:", t)
    }
}()

在这个例子中,我们使用 range 代替了 select 语句。这样,每个定时器都会在自己的循环中等待自己的通道被填充,从而实现了同步。

2 个回答

1 读了两次,是两个周期。

可以直接写 case t := <-ticker1.C

ticker1.C是一个管道,select case <- ticker1.C 实际上就已经读取了一次管道了。下面的t := <- ticker1.C 是读取第二次。定时器每隔3s向ticker1.C写入一次时间。你等待第二次读,不就是6s才会输出ticker1的时间吗。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题