用 time.Ticker 适合秒级/毫秒级轻量周期任务,但需防 tick 积压和 goroutine 泄漏;cron/v3 适合表达式调度,需处理 panic、并发与时区;禁用 time.AfterFunc 做重复任务。
time.Ticker 实现简单周期任务适合秒级或毫秒级固定间隔的轻量任务,比如每 5 秒检查一次本地缓存状态。它不处理任务执行超时、失败重试或并发冲突,只保证“按表走时”。
time.Ticker 启动后立即发送第一个 tick,若任务执行时间 > 间隔,后续 tick 会堆积在 channel 中,可能引发 goroutine 泄漏ticker.Stop(),否则 goroutine 和 timer 资源不会释放for range ticker.C 循环里直接写耗时逻辑,应起 goroutine 或用带超时的 context 控制ticker := time.NewTicker(5 * time.Second) defer ticker.Stop()for range ticker.C { go func() { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() // 执行实际任务 doWork(ctx) }() }
github.com/robfig/cron/v3 做类 crontab 调度需要按时间表达式(如 "0 0 * * *)触发的任务,比如每天凌晨 2 点清理日志。这是目前最稳定、文档最全的 Go cron 库。
Seconds 字段(支持秒级),v2 不支持,初始化时注意传 cron.WithSeconds()
cron.Cron 实例,但每个 job 的执行是串行的(除非手动启 goroutine)c := cron.New(cron.WithSeconds())
c.AddFunc("0 0/5 * * * ?", func() {
defer func() {
if r := recover(); r != nil {
log.Printf("job panicked: %v", r)
}
}()
cleanupLogs()
})
c.Start()
defer c.Stop()time.AfterFunc 做重复定时任务它只执行一次,常见误用是“递归调用自己”来模拟循环,这会累积 goroutine 和 timer,且无法统一管理生命周期。
time.AfterFunc(d, f) 在 f 末尾再调一次 AfterFunc
本地测试跑得通,上线后常因这些被卡住:
立即学习“go语言免费学习笔记(深入)”;
cron 默认用本地时区,容器中往往为 UTC,用 cron.WithLocation(time.UTC) 显式指定github.com/go-co-op/gocron)log.Printf("[job:%s] start", name) 和 defer 日志定时任务最难的不是怎么启动,而是怎么让它在机器
重启、部署更新、网络抖动后依然可靠运行。别省那几行日志和锁逻辑。