Go 执行定时任务
在 Go 中实现定时任务有多种方法,以下是常见且实用的实现方式。
# 单次延迟任务
如果只需要在特定时间后执行一次任务,通常使用 time.After
或 time.Sleep
。
func main() {
fmt.Println("任务将在 5 秒后执行...")
time.Sleep(5 * time.Second) // 延迟 5 秒
doTask()
// 或者使用 time.After
<-time.After(5 * time.Second) // 等待 5 秒
fmt.Println("5 秒已到!")
doTask()
}
func doTask() {
fmt.Println("执行定时任务...")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
特点:
- 适合简单的单次延迟任务。
time.Sleep
会阻塞当前 goroutine,time.After
返回一个通道,可用于非阻塞场景。
# 周期性的定时任务
time.Ticker
适合需要周期性执行的任务,比如每隔一段时间运行一次。
func main() {
// 创建一个每隔 2 秒触发的 Ticker
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop() // 确保在程序结束时停止 Ticker
for {
select {
case t := <-ticker.C:
fmt.Println("任务执行时间:", t)
// 在这里执行你的定时任务逻辑
doTask()
}
}
}
func doTask() {
fmt.Println("执行定时任务...")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 动态调整时间
如果需要动态调整定时时间,可以使用 time.Timer。
func main() {
timer := time.NewTimer(3 * time.Second)
for {
<-timer.C
fmt.Println("任务执行时间:", time.Now())
doTask()
// 重置定时器,可以动态调整时间
timer.Reset(5 * time.Second)
}
}
func doTask() {
fmt.Println("执行定时任务...")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 在特定时刻执行
func main() {
for {
now := time.Now()
// 将当前时间截断到整点,然后加上5分钟,得到下一个整点时间
next := now.Truncate(time.Hour).Add(time.Hour + 5*time.Minute)
// 如果当前时间已经超过 next,则将 next 推迟到下个小时
if now.After(next) {
next = next.Add(time.Hour)
}
// 计算需要睡眠的时长
sleepDuration := next.Sub(now)
time.Sleep(sleepDuration)
// 执行任务
doTask()
}
}
func doTask() {
fmt.Println("执行定时任务...")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 对于复杂的定时任务
如果需要类似 cron 的调度功能(比如“每天 8 点执行”),可以使用第三方库 github.com/robfig/cron (opens new window)。
它是一个用于 Go 语言的强大且流行的 cron 调度库,它允许开发者在指定的时间或周期性调度任务。它最初由 Rob Figueiredo(robfig)开发,目前已经成为 Go 生态系统中处理定时任务的常用工具之一。该库的主要功能是解析 cron 表达式并根据时间表运行注册的任务,支持灵活的调度需求。
# 主要功能
- Cron 表达式解析:
- 支持标准的 cron 表达式(例如 0 0 * * * 表示每小时整点执行)。
- 默认使用标准的 5 字段格式(分钟、小时、日、月、星期),也可以通过选项支持 6 字段格式(包括秒)。
- 提供预定义的快捷方式,例如
@hourly
(每小时)、@daily
(每天)、@every 1h30m
(每隔 1 小时 30 分钟)。
- 任务调度:
- 允许注册函数(Func)作为任务,在指定时间自动执行。
- 任务运行在独立的 goroutine 中,不会阻塞主程序。
- 灵活的配置:
- 支持时区设置,可以通过 CRON_TZ 前缀指定任务运行的时区。
- 提供函数式选项(functional options)来定制调度器的行为,例如日志记录、panic 恢复等。
- 动态管理:
- 支持在调度器运行时动态添加或移除任务。
- 可以检查任务的下一次和上一次运行时间。
- 日志和错误处理:
- 内置日志接口(兼容 github.com/go-logr/logr),支持详细日志记录。
- 通过 JobWrapper 和 Chain 机制支持任务的拦截器,例如跳过仍在运行的任务或记录执行日志。
package main
import (
"fmt"
"github.com/robfig/cron/v3"
"time"
)
func main() {
// 创建一个新的 cron 调度器
c := cron.New()
// 每小时整点执行
c.AddFunc("0 * * * *", func() {
fmt.Println("每小时执行:", time.Now())
})
// 每天凌晨 0 点执行
c.AddFunc("0 0 * * *", func() {
fmt.Println("每天凌晨执行:", time.Now())
})
// 每隔 1 小时 30 分钟执行
c.AddFunc("@every 1h30m", func() {
fmt.Println("每隔1小时30分钟执行:", time.Now())
})
// 启动调度器
c.Start()
// 防止主程序退出
select {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
标准 cron 表达式由 5 个字段组成(默认不支持秒,需通过 WithSeconds 启用)
cron.New(cron.WithSeconds()) // 启用秒级调度
1
上次更新: 2025/04/09, 14:47:54