调度单个cron
- 这写代码的老师都喜欢用var 声明变量后使用
- 下次调度时间: nextTime = expr.Next(now)
- 超时时间计算:nextTime.Sub(now)
- 超时后执行回调函数:time.AfterFunc
// 【github.com/gorhill/cronexpr】 这个包功能对应Linux的定时任务;但是这个包支持到秒级
/*
秒---> 0-59
分---> 0-59
时---> 0-23 0表示0点
日---> 1-31
月---> 1-12
周---> 0-6 0表示周日
年---> 1-12
*/
package main
import (
"fmt"
"time"
"github.com/gorhill/cronexpr"
)
func main() {
var (
err error
expr *cronexpr.Expression
now time.Time // 当前时间
nextTime time.Time // 下次调度时间
)
// 每5s执行一次
if expr, err = cronexpr.Parse("*/5 * * * * * *"); err != nil {
fmt.Println(err)
return
}
// 当前时间
now = time.Now()
// 下次调度时间 [时间规律是0,6,12,18,...,58],而不是根据启动时间计算的
nextTime = expr.Next(now)
// 等待这定时器超时
// 超时时间计算:nextTime.Sub(now)
time.AfterFunc(nextTime.Sub(now), func() {
// 超时就会执行这回调函数
fmt.Println("被调度了", nextTime)
})
time.Sleep(6 * time.Second)
}
调度多个cron任务
package main
import (
"fmt"
"time"
"github.com/gorhill/cronexpr"
)
// 任务结构体--封装
type CronJob struct {
expr *cronexpr.Expression // 时间表达式
nextTime time.Time // 下次调度时间
}
// 声明一些全局变量
var (
cronJob *CronJob // job名字
expr *cronexpr.Expression // 时间表达式
now time.Time // 当前时间
scheduleTable map[string]*CronJob //key:任务名字, 调度表 存放所有定时任务
)
func main() {
// 需要有一个调度协程,让他定时检测所有的Corn任务,谁过期了就执行谁
// 当前时间
now = time.Now()
// 创建内存,map不可以直接使用,这里不给分配内存
scheduleTable = make(map[string]*CronJob)
// 定义两个cornjob: 每5s执行一次; 每57执行一次
expr = cronexpr.MustParse("*/5 * * * * * *")
// 将调度器CronJob初始化且赋值给cronJob
cronJob = &CronJob{
expr: expr,
nextTime: expr.Next(now),
}
// 任务注册到调度表
scheduleTable["job1"] = cronJob
// 定义两个cornjob: 每5s执行一次; 每57执行一次
expr = cronexpr.MustParse("*/5 * * * * * *")
// 将调度器CronJob初始化且赋值给cronJob
cronJob = &CronJob{
expr: expr,
nextTime: expr.Next(now),
}
// 任务注册到调度表
scheduleTable["job2"] = cronJob
// 启动调用协程
go func() {
var (
jobName string
cronJob *CronJob
now time.Time
)
// 定时检查一下调度任务
for {
now = time.Now()
// 判断是否过期(如果下次调度时间小于等于当前时间,说明已经过期了)
for jobName, cronJob = range scheduleTable {
if cronJob.nextTime.Before(now) || cronJob.nextTime.Equal(now) {
// 启动一个协程,执行这任务
go func(jobName string) {
fmt.Println("执行:", jobName)
}(jobName)
// 计算下一次调度时间
cronJob.nextTime = cronJob.expr.Next(now)
fmt.Println(jobName, "下次执行时间是:", cronJob.nextTime)
}
}
// 睡眠100 毫秒(不让它占用过多cpu)
select {
case <-time.NewTimer(100 * time.Millisecond).C: //将在100 毫秒可读,返回
}
// 简单的 time.Sleep(100 *time.Second)
}
}()
time.Sleep(100 * time.Second)
}
# 实际效果
job1 下次执行时间是: 2022-03-15 00:54:45 +0800 CST
执行: job1
job2 下次执行时间是: 2022-03-15 00:54:45 +0800 CST
执行: job2
执行: job1
job1 下次执行时间是: 2022-03-15 00:54:50 +0800 CST
job2 下次执行时间是: 2022-03-15 00:54:50 +0800 CST
执行: job2
job1 下次执行时间是: 2022-03-15 00:54:55 +0800 CST
job2 下次执行时间是: 2022-03-15 00:54:55 +0800 CST
执行: job1
执行: job2
执行: job1
job1 下次执行时间是: 2022-03-15 00:55:00 +0800 CST
执行: job2
job2 下次执行时间是: 2022-03-15 00:55:00 +0800 CST
执行: job1
job1 下次执行时间是: 2022-03-15 00:55:05 +0800 CST
job2 下次执行时间是: 2022-03-15 00:55:05 +0800 CST