简体   繁体   English

Golang for select 循环消耗 100% 的 cpu

[英]Golang for select loop consumes 100% of cpu

I have a resource that needs to be loaded before any access is allowed to it.我有一个需要加载的资源,然后才允许对其进行任何访问。 It also needs to be updated every minute.它还需要每分钟更新一次。

The channels are of length 1 struct{}, so the loop will be blocked if the resource has not been loaded.通道的长度为 1 struct{},因此如果资源尚未加载,则循环将被阻塞。

This code below started to use 100% of my cpu, I tried adding下面的这段代码开始使用我 100% 的 cpu,我尝试添加

time.Sleep(10 * time.Millisecond)

Which made the application cpu consumption drop to 1%这使得应用程序cpu消耗下降到1%

I am thinking a ticker would be a better option for the timed collection.我认为自动收报机将是定时收藏的更好选择。

Any ideas why it would consume 100% cpu or any better ideas for implemention?任何想法为什么它会消耗 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
            }
        }
    }()
}

I think you just post to al.chanFetchRequest when there is new data so I think you have to keep reading from this channel all the time.我认为你只是在有新数据时发布到 al.chanFetchRequest 所以我认为你必须一直从这个频道阅读。 Adding a ticker to the select might cause you to fetch the data even if it has not changed or (worse) before it has even loaded.向选择中添加代码可能会导致您获取数据,即使它没有更改或(更糟)在它加载之前。 Why not, in the normal case, take the time whenever you fetch the data then the next time make sure you have waited enough time before fetching again.为什么不,在正常情况下,每次获取数据时都花点时间,然后确保在再次获取数据之前等待了足够的时间。 Something like this:像这样的东西:

        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{}{}
            }
        }

default statement creates a nonblocking infinite loop that leads 100% cpu usage. default语句创建一个非阻塞无限循环,导致 100% 的 cpu 使用率。 When the condition for case is not satisfied, the loop goes to the default nonblocking infinite loop.当 case 的条件不满足时,循环进入默认的非阻塞无限循环。

Removing default will resolve the issue.删除default将解决问题。 But there will be a linter warning S1000: should use for range instead of for { select {} } to inform that select is meaningless with single channel.但是会有一个 linter 警告S1000: should use for range instead of for { select {} }通知select对单通道没有意义。

The final code will be最终代码将是

for {
    _ := <-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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM