【问题标题】:Golang for select loop consumes 100% of cpuGolang for select 循环消耗 100% 的 cpu
【发布时间】:2019-03-26 22:43:43
【问题描述】:

我有一个资源需要先加载,然后才能对其进行任何访问。它也需要每分钟更新一次。

通道的长度为 1 struct{},因此如果资源尚未加载,则循环将被阻塞。

下面这段代码开始占用我 100% 的 cpu,我尝试添加

time.Sleep(10 * time.Millisecond)

这使得应用cpu消耗下降到1%

我认为自动收报机是定时收集的更好选择。

任何想法为什么它会消耗 100% cpu 或任何更好的实现想法?

func (al *AsyncLoop) Run() {
    go func() {
        for {
            select {
            case <-al.chanFetchRequest:
                if al.fetched == false {
                    al.fetchData()
                } else if al.lastUpdated.Add(1*time.Minute).Unix() < time.Now().Unix() && al.fetching == false {
                    go al.fetchData()
                }
                al.chanFetchResponse <- struct{}{}
                continue
            default:
                continue
            }
        }
    }()
}

【问题讨论】:

  • 您的选择中有一个默认情况,这意味着如果从 al.al.chanFetchRequest 中没有可读取的内容,for 循环将旋转。
  • 同时查看al.lastUpdatedscp.fetchinggo al.fetchData() 也有可能在此代码中存在数据竞争。
  • 是的,感谢您发现这一点,我将添加一些带有互斥锁的 get 和 set 方法

标签: go cpu


【解决方案1】:

我认为你只是在有新数据时发布到 al.chanFetchRequest,所以我认为你必须一直从这个频道继续阅读。向选择添加一个代码可能会导致您获取数据,即使它没有更改或者(更糟)甚至在加载之前。为什么不呢,在正常情况下,每次获取数据时都要花时间,然后确保在再次获取之前等待足够的时间。像这样的:

        var nextFetch time.Time
        for {
            select {
            case <-al.chanFetchRequest:
                if al.fetched == false {
                    al.fetchData()
                    nextFetch = time.Now().Add(1 * time.Minute)
                } else if time.Now().After(nextFetch) {
                    al.fetchData()
                    nextFetch = time.Now().Add(1 * time.Minute)
                }
                al.chanFetchResponse <- struct{}{}
            }
        }

【讨论】:

  • 单格选择没有意义。只需从频道中阅读。
  • @Adrian 谢谢 - 你是对的,这正是我在第二个回答中所说的(如下)。但是,如果您认为稍后会添加其他案例,它可能会很有用。
猜你喜欢
  • 1970-01-01
  • 2012-09-25
  • 2012-01-26
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
相关资源
最近更新 更多