在后端服务、日志采集、数据清洗、健康检查等应用中,我们经常需要实现“每隔一段时间执行某个任务”。Go 标准库 time 包提供了非常强大且简洁的支持,配合协程可轻松构建定时任务调度器。


一、需求背景

我们希望实现一个任务调度器,能够:

  • 每隔固定时间执行某个函数;
  • 支持并发安全;
  • 可停止调度器(支持任务终止);
  • 可扩展多个任务调度。

二、实现方案一:使用 time.Ticker

Go 的 time.Ticker 提供了周期性触发的功能。配合 selectgoroutine 可实现高效的调度器。

示例:每 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 执行数据备份

五、注意事项

  1. 资源释放: 使用 time.Ticker 时,一定要在停止时调用 ticker.Stop(),否则会泄露定时器资源。

  2. 线程安全: 如果调度器涉及状态管理(如是否运行中),需要使用 sync.Mutex 加锁保护。

  3. 协程退出机制: 使用 chan struct{} 来安全地关闭 goroutine 是一种推荐方式。


六、进阶建议

  • 可结合 context.Context 实现更细粒度的取消控制;
  • 支持动态更改调度时间(重设 ticker);
  • 结合 cron 表达式(第三方库如 robfig/cron)实现更复杂的计划任务;
  • 支持任务失败重试与日志记录机制。

七、结语

通过 time.Ticker 和 goroutine,Go 可以非常优雅地实现定时任务调度器。虽然标准库方案简单,但足以应对大多数日常应用。你可以在此基础上封装出强大的任务调度框架,用于后台服务、数据处理、定时推送等业务场景。