在后端服务、日志采集、数据清洗、健康检查等应用中,我们经常需要实现“每隔一段时间执行某个任务”。Go 标准库
time
包提供了非常强大且简洁的支持,配合协程可轻松构建定时任务调度器。
一、需求背景
我们希望实现一个任务调度器,能够:
- 每隔固定时间执行某个函数;
- 支持并发安全;
- 可停止调度器(支持任务终止);
- 可扩展多个任务调度。
二、实现方案一:使用 time.Ticker
Go 的 time.Ticker
提供了周期性触发的功能。配合 select
和 goroutine
可实现高效的调度器。
示例:每 2 秒执行一次任务
package mainimport ("fmt""time"
)func task() {fmt.Println("任务执行时间:", time.Now())
}func main() {ticker := time.NewTicker(2 * time.Second)defer ticker.Stop()done := make(chan bool)go func() {for {select {case <-done:fmt.Println("调度器已停止")returncase t := <-ticker.C:fmt.Println("调度器触发:", t)task()}}}()// 模拟运行一段时间后终止time.Sleep(10 * time.Second)done <- true
}
输出示例:
调度器触发:2025-08-05 20:00:00
任务执行时间:2025-08-05 20:00:00
调度器触发:2025-08-05 20:00:02
任务执行时间:2025-08-05 20:00:02
...
调度器已停止
三、实现方案二:封装通用任务调度器结构体
为了更灵活地管理多个任务,我们可以封装一个 Scheduler
类型。
type TaskFunc func()type Scheduler struct {ticker *time.Tickerquit chan struct{}running boolmu sync.Mutex
}func NewScheduler(interval time.Duration, task TaskFunc) *Scheduler {return &Scheduler{ticker: time.NewTicker(interval),quit: make(chan struct{}),running: false,}
}func (s *Scheduler) Start(task TaskFunc) {s.mu.Lock()if s.running {s.mu.Unlock()return}s.running = trues.mu.Unlock()go func() {for {select {case <-s.quit:returncase <-s.ticker.C:task()}}}()
}func (s *Scheduler) Stop() {s.mu.Lock()defer s.mu.Unlock()if s.running {close(s.quit)s.ticker.Stop()s.running = false}
}
使用示例:
func main() {scheduler := NewScheduler(3*time.Second, nil)scheduler.Start(func() {fmt.Println("执行任务:", time.Now())})time.Sleep(10 * time.Second)scheduler.Stop()fmt.Println("调度器停止")
}
四、任务调度器使用场景举例
场景 | 调度内容 |
---|---|
日志清理 | 每天凌晨清除旧日志 |
服务心跳 | 每 5 秒上报健康状态 |
数据同步 | 每小时同步远程数据 |
自动备份 | 每天 23:00 执行数据备份 |
五、注意事项
-
资源释放: 使用
time.Ticker
时,一定要在停止时调用ticker.Stop()
,否则会泄露定时器资源。 -
线程安全: 如果调度器涉及状态管理(如是否运行中),需要使用
sync.Mutex
加锁保护。 -
协程退出机制: 使用
chan struct{}
来安全地关闭 goroutine 是一种推荐方式。
六、进阶建议
- 可结合
context.Context
实现更细粒度的取消控制; - 支持动态更改调度时间(重设 ticker);
- 结合
cron
表达式(第三方库如robfig/cron
)实现更复杂的计划任务; - 支持任务失败重试与日志记录机制。
七、结语
通过 time.Ticker
和 goroutine,Go 可以非常优雅地实现定时任务调度器。虽然标准库方案简单,但足以应对大多数日常应用。你可以在此基础上封装出强大的任务调度框架,用于后台服务、数据处理、定时推送等业务场景。