不使用库实现Golang定时器

不使用库实现Golang定时器 大家好! 如何在不使用第三方库的情况下,每天凌晨1点执行函数? 类似这样:

func RunAtNight() {
    for {
            do something.....
            time.Sleep(time.Second * 1) //但要在每天凌晨1点执行
     }
}

谢谢!

6 回复

谢谢!全部正常工作了!

更多关于不使用库实现Golang定时器的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


太棒了! 谢谢!

如果我们需要能够以某种方式取消预定的运行,上述方法也很有用。

计算下一次执行的时间,然后休眠直到该时刻。

func RunAtNight() {
    for {
        do something.....

        // 明天,与当前相同的时间点
        tomorrow := time.Now().AddDate(0, 0, 1)
        // 下一次执行时间为明天凌晨1点
        next := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 1, 0, 0, 0, time.Local)
        // 休眠直到指定时间
        time.Sleep(time.Until(next))
    }
}

对于这类情况,我发现自己通常只睡眠预期时间的一半。这样我就能理想地修正睡眠期间可能发生的任何延迟,同时输出日志行以便知道计时器仍在等待到适当的时间…所以在上述代码示例中,我会改为这样做:

func RunAtNight() {
    for {
        do something.....

        // Tomorrow, same time as now.
        tomorrow := time.Now().AddDate(0, 0, 1)
        // Next run is tomorrow, at 1 AM
        next := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 1, 0, 0, 0, time.Local)

        if tu := time.Until(next); tu <= 60 * time.Second {
            // log something here
            // Sleep until then.
            time.Sleep(tu)
        else {
            // log something here
            // Sleep until half of then.
            time.Sleep(tu / 2)
        }
    }
}

你可以使用标准库的 time 包来实现每天凌晨1点执行函数的需求。关键在于计算当前时间到下一个凌晨1点的时间间隔,然后使用 time.Sleeptime.After 等待。以下是两种实现方式:

方法1:使用 time.Sleep 循环执行

package main

import (
    "fmt"
    "time"
)

func RunAtNight() {
    for {
        now := time.Now()
        next := now.Add(time.Hour * 24)
        next = time.Date(next.Year(), next.Month(), next.Day(), 1, 0, 0, 0, next.Location())
        duration := next.Sub(now)
        
        fmt.Printf("等待 %v 直到下一次执行\n", duration)
        time.Sleep(duration)
        
        // 执行你的任务
        fmt.Printf("执行任务,当前时间: %v\n", time.Now())
    }
}

func main() {
    RunAtNight()
}

方法2:使用 time.After 和 select 语句

package main

import (
    "fmt"
    "time"
)

func RunAtNight() {
    for {
        now := time.Now()
        next := now.Add(time.Hour * 24)
        next = time.Date(next.Year(), next.Month(), next.Day(), 1, 0, 0, 0, next.Location())
        duration := next.Sub(now)
        
        fmt.Printf("等待 %v 直到下一次执行\n", duration)
        <-time.After(duration)
        
        // 执行你的任务
        fmt.Printf("执行任务,当前时间: %v\n", time.Now())
    }
}

func main() {
    RunAtNight()
}

关键点说明:

  1. 计算下一次执行时间

    • 获取当前时间 now := time.Now()
    • 计算明天的日期 next := now.Add(time.Hour * 24)
    • 设置时间为凌晨1点:time.Date(next.Year(), next.Month(), next.Day(), 1, 0, 0, 0, next.Location())
  2. 等待时间计算

    • 使用 next.Sub(now) 得到需要等待的时间间隔
  3. 执行循环

    • 每次执行完成后重新计算下一次的等待时间

注意事项:

  • 这种方法会在每天凌晨1点准时执行一次
  • 如果程序在睡眠期间被终止,下次启动时会重新计算等待时间
  • 考虑使用 time.Ticker 的替代方案可能更精确,但需要更复杂的时间计算

两种方法都能实现你的需求,选择哪种取决于你的具体偏好。方法1使用 time.Sleep 更直观,方法2使用 time.After 可以更容易地与其他通道操作集成。

回到顶部