【问题标题】:Goroutine select loop with Ticker causes CPU to 100%带有 Ticker 的 Goroutine 选择循环导致 CPU 达到 100%
【发布时间】:2020-09-14 06:50:30
【问题描述】:

我有这个循环,它的作用是尝试反复轮询另一台服务器。我使用ticker来实现这一点,但是程序反复显示100%的CPU使用率。

这个代码在一个 goroutine 中运行。 HTTP 服务器在另一个 goroutine 中运行。


func() Monitor() {

  abort := make(chan bool)

  log.Info("Monitor started.")

  // start the monitor goroutine
  go func() {
      defer log.Info("Stopped monitor")
        
      ticker := time.NewTicker(time.Duration(35.0) * time.Second)
      defer ticker.Stop()
        
      log.Info("Monitor started! \n")
      for {
        select {
        case t := <-ticker.C:
            log.Infof("Subscribe to service at time %v\n", t)
            if err := selfConn.SubscribeToService(); err != nil {
                log.Errorf("Failed to subscribe to primary connector: %v", err)
            } 
        case <-abort:
            log.Info("Finished routine!")
            return
        default:
            continue
        }
        }
    }() 
  
    go func() {
        time.Sleep(10 * time.Minute)
        abort <- true
    }()
}

但是当监视器循环开始时,每次发送到股票通道的信号时,CPU 一直显示 100%。

在 goroutine 中使用 ticker 以使其不会消耗 100% 的 CPU,我错过了什么?

【问题讨论】:

  • 您能否就您对该问题投反对票的原因发表评论?这是我在社区提出的第一个问题,最近在学习 Go 并发。在网站上发布我的下一个问题会对我有所帮助。

标签: go cpu cpu-usage goroutine ticker


【解决方案1】:

您的循环中有一个 select 和一个 default 分支。如果其他cases 都没有准备好继续,default 分支将立即执行,因此您的下一次迭代立即开始而无需等待。这是一个繁忙的循环。

另外,不需要另一个 goroutine 终止,你可以在同一个 goroutine 中使用计时器。

例如:

func monitor() {
    log.Info("Monitor started.")

    ticker := time.NewTicker(35 * time.Second)
    defer ticker.Stop()

    timeoutCh := time.After(10 * time.Minute)
    for {
        select {
        case t := <-ticker.C:
            log.Infof("Subscribe to service at time %v\n", t)
            if err := selfConn.SubscribeToService(); err != nil {
                log.Errorf("Failed to subscribe to primary connector: %v", err)
            }
        case <-timeoutCh:
            log.Info("Finished routine!")
            return
        }
    }
}

【讨论】:

  • 非常感谢!是的,我删除了默认值,它的表现要好得多。你是对的 :) 例如,我刚刚添加了终止计时器,它应该是 10 分钟,轮询间隔为 35 秒。你的例子就是我要找的:)。谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 2020-10-06
  • 2010-11-16
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多