go - 有没有更好的选择去使用常规 sleep

标签 go sleep goroutine thread-sleep

我想写一个每工作1小时要说一次的 worker 。截至目前,我们的系统中没有Cron,因此不想添加cron。在后续实现中提出建议:

func init(){
     go startWorker()
}

func startWorker(){
     doJob()
     time.Sleep(time.Second * 3600)
}

在日常工作中使用 sleep 是个坏主意,还是有更好的选择来做这样的事情。doJob()的工作是从数据库中获取最近一个小时内发生的所有故障,然后重试

最佳答案

按照您的设想使用time.Sleep有两个问题,一个主要和一个次要。

您无法终止goroutine

goroutine陷入无限循环,因此,除非doJob出现 panic ,否则它将永远不会终止。您可能应该向它传递一个 channel ,该 channel 在goroutine需要终止时将被关闭:

done := make(chan struct{})
go worker(done)
...
close(done)
...
func worker(done <-chan struct{}){
    for {
        doJob()
        timer := time.NewTimer(time.Hour)
        select {
        case <-timer.C:
            // nothing
        case <-done:
            timer.Stop()
            return
        }
    }
}

或者,更好的是,使用代码:

func worker(done <-chan struct{}){
    ticker := time.NewTicker(time.Hour)
    for {
        doJob()
        select {
        case <-ticker.C:
            // nothing
        case <-done:
           ticker.Stop
           return
        }
    }
}

这是使用defer的好样式:

func worker(done <-chan struct{}){
    ticker := time.NewTicker(time.Hour)
    defer ticker.Stop()
    for {
        doJob()
        select {
        case <-ticker.C:
            // nothing
        case <-done:
           return
        }
    }
}

你在浪费堆栈

当goroutine使用微不足道的CPU资源时,它使用的堆栈大约为十几千字节。对于您来说,这可能不是问题,但如果是这样,并且如果您的应用程序具有主循环,则可以将代码和doWork的调用插入到主循环的主select语句中。

关于go - 有没有更好的选择去使用常规 sleep ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62159498/

相关文章:

Golang 对 VSTS Git 的支持

java - 为什么 Thread.sleep() 或 TimeUnit.SECONDS.sleep() 延迟执行先前的语句而不是从调用 sleep() 的地方暂停

Goroutine 仅在执行 fmt.Println 时起作用

go - 多 Go-Routine 循环未按预期执行

go - 如果下一条记录依赖于上一条记录怎么办,我可以使用 goroutine 吗?如果是的话怎么办?

go - 动态添加Kafka主题以从中使用,而无需重新启动GoLang应用程序

.htaccess - 没有 Nginx 或 Apache 的 Golang htaccess 配置

iphone - 用户交互后刷新屏幕

Python 在不干扰脚本的情况下休眠?

go - 如何测试此功能的错误条件?