go从0到1项目实战体系七十七:cron表达式

1. linux基本格式:

    *        *         *         *        *
(0-59)  (0-23)  (1-31)  (1-12)  星期(0-7). *表示任意分、时、日、月、星期
②. ,表示并行
③. -表示连续,[m, n]闭区间,执行了(m - n + 1)次
④. /表示整除

(1). 举例:

20 * * * * shell                        每个小时的第20分钟执行
20,40 * * * * shell                     每个小时的第20分钟、第40分钟执行
20-40 * * * * shell                     每个小时的第20分钟到第40分钟(21)执行
*/2 * * * * shell                       每个小时的分钟可以被2整除的都会(0, 2, 4, ..., 58)执行
*/5 * * * * echo hello > /tmp/x.log     每隔5分钟执行11-5 * * * * /usr/bin/python /data/x.py  第1-5分钟执行50 10,22 * * * echo bye | tail -1        每天1022点整执行1

(2). 整除:

*/2    0, 2, 4,  ..., 582整除的分钟
0/2    0, 2, 4,  ..., 58    等价上面
1/2    1, 3, 5,  ..., 59    前面指定了特定的数字,表示时间点减去这个数字,再看能不能被2整除
7/2    7, 9, 11, ..., 59    时间点减去这个数字,如果是负数,就不考虑了.

(3). 坑:

. 星期:
    a. 由于linux版本的问题,有的版本星期有些可能是0-6,有些可能是1-7,有些1代表星期天
    b. 可以用简写来代替,Cron支持配置星期缩写:MON TUE WED THU FRI SAT SUN
       * * * * * MON-FRI
    c. 还可以用W指定工作日(周一到周五). 月份:
    a. 简写:
       一月Jan、二月Feb、三月Mar、四月Apr、五月May、六月Jun、七月Jul、八月Aug、九月Sep、十月Oct、十一月Nov、十二月Dec

③.:
    a. 指定L字段表示每个月最后一天

(4). 怎么每秒执行?

* * * * * shell
* * * * * sleep 1;shell
...
* * * * * sleep 59;shell

:
两个59个脚本都是在同一分钟执行,由于sleep了.就会从0秒到59秒都有脚本执行.

(5). cron执行原理:

已知当前UNIX时间为1532659200,即2018/07/27 10:40:00
已知道Cron表达式是30 * * * *
如何计算命令的下次调度时间?

当前时间: 2018/07/2710:40:00
401027日
          ↓           +20
001127日
          ↓           +30
301127日

  下次调度时间:2018/07/27 11:30:00

Cron: 30 * * * *

枚举:
分钟: [З0]
小时: [0,1,2..23]
日期: [1,2,.31]
月份: [1,2...12]

4. go的cron解析库(Cronexpr库):

(1). 安装:

go get -u "github.com/gorhill/cronexpr"

(2). 示例1:

import "github.com/gorhill/cronexpr"

func main() {
	var (
		expr *cronexpr.Expression
		err error
		now time.Time
		nextTime time.Time
	)
	// 7位表达式:增加了秒、和年(2018 - 2099)
	if expr, err = cronexpr.Parse("*/5 * * * * * *"); err != nil {       // Parse():解析与校验Cron表达式
		fmt.Print(err)
		return
	}
	now = time.Now()            // 当前时间
	nextTime = expr.Next(now)   // 下次调度时间,Next()方法是根据当前时间,计算下次调度时间.
    fmt.Print(now, nextTime)
    // */5(每5分钟执行一次):
    // 2020-07-05 21:24:00  2020-07-05 21:25:00
    // */6(每6分钟执行一次):
    // 2020-07-05 21:25:25 2020-07-05 21:30:00
    // 0, 6, 12, 18, ..., 48

	// 等待定时器超时
	time.AfterFunc(nextTime.Sub(now), func () {      // 计算差值
		fmt.Print("被调度了")
	})
    // 需要阻塞主进程,否则上面没执行完就主进程退出了
	time.Sleep(5* time.Second)
}

(3). 示例:

type CronJob struct {
	expr *cronexpr.Expression
	nextTime time.Time
}
func main() {
	// 把所有的Cron任务存放到一个地方
	// 需要1个调度协程,它定时检查/扫描所有的Cron任务,谁过期就执行谁
	var (
		cronJob *CronJob
		expr *cronexpr.Expression
		now time.Time
		scheduleTable map[string]*CronJob  // key是任务名字
	)
	scheduleTable = make(map[string]*CronJob)
	now = time.Now()
	// MustParse进行断言,觉对不会出错
	expr = cronexpr.MustParse("*/5 * * * * * *")
	cronJob = &CronJob{
		expr: expr,
		nextTime: expr.Next(now),
	}
	// 任务注册到调度表中
	scheduleTable["job1"] = 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.Print(jobName)
					}(jobName)
					// 计算下一次调度时间
					cronJob.nextTime = cronJob.expr.Next(now)
					fmt.Println(jobName, cronJob.nextTime)
				}
			}
			// 睡眠100毫秒
			select {
				case <- time.NewTimer(100 * time.Millisecond).C:  // 将在100毫秒可读,返回
			}
		}
	}()

	time.Sleep(100 * time.Second)
}
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值