• GO实现Cron解析和定时任务


    Go的Cron表达式解析库:github.com/gorhill/cronexpr

    核心类型和方法

    // 表达式对象
    expr *cronexpr.Expression
    // 解析cron表达式
    expr = cronexpr.Parse()
    // 返回下次执行时间
    expr.Next()
    

    解析Cron表达式

    func PrintCronNext() {
    	var (
    		cronLine string
    		expr *cronexpr.Expression
    	)
    	// 定时参数的格式 秒 分 时 日 月 周 年
    	cronLine = "*/5 * * * * * *"
    	expr, _ = cronexpr.Parse(cronLine)
    	// expr.Next基于某个时间给出下一次的执行时间
    	fmt.Println(expr.Next(time.Now()))
    	// expr.NextN返回多个Next时间
    	fmt.Println(expr.NextN(time.Now(), 5))
    }
    

    执行定时任务

    // 结合time.AfterFunc实现定时任务的执行
    func ExecWithCronNext() {
    	var (
    		cronLine string
    		expr *cronexpr.Expression
    	)
    	cronLine = "*/5 * * * * * *"
    	expr, _ = cronexpr.Parse(cronLine)
    	// AfterFunc用于在指定的Duration后执行相应的函数
    	// expr.Next() - time.Now() 得到相应的Duration
    	time.AfterFunc(expr.Next(time.Now()).Sub(time.Now()), func() {
    		fmt.Println("定时任务被执行了")
    	})
    	// 挂起主线程
    	time.Sleep(10 * time.Second)
    }
    

    实现定时任务循环调度

    // 封装一个任务
    type CronJob struct {
    	expr *cronexpr.Expression
    	nextTime time.Time
    	job func()  // 传递要执行的任务
    }
    // 构建调度器实现循环调度
    func ScheduleWithCron() {
    	// 调度器的本质是要循环一个调度表实现调度
    	var (
    		cronLine string
    		expr *cronexpr.Expression
    		cronJob *CronJob
    		scheduleTable map[string]*CronJob
    	)
    	cronLine = "*/5 * * * * * *"
    	// MustParse在Parse基础上当有err出现时进行Panic
    	expr = cronexpr.MustParse(cronLine)
    	// 新建任务
    	cronJob = &CronJob{
    		expr:     expr,
    		nextTime: expr.Next(time.Now()),
    		job: func() {
    			fmt.Println("do cron job")
    		},
    	}
    	// map类型需要make进行内存分配
    	scheduleTable = make(map[string]*CronJob)
    	// 将任务添加到调度表
    	scheduleTable["job1"] = cronJob
    
    	// 启动调度goroutine实现遍历调度表
    	go func() {
    		var (
    			jobName string
    			cronJob *CronJob
    			now time.Time
    		)
    		for {
    			now = time.Now()
    			// range是go中的遍历语法
    			for jobName, cronJob = range scheduleTable {
    				// 比较每个CronJob中的NextTime是否已经过期
    				if cronJob.nextTime.Before(now) || cronJob.nextTime.Equal(now) {
    					// 如果已经过期或者刚好相等,则启动一个goroutine来执行任务
    					go func() {
    						fmt.Printf("开始执行任务: %s 
    ", jobName)
    						cronJob.job()
    					}()
    					// 更新一下NextTime
    					cronJob.nextTime = cronJob.expr.Next(now)
    				}
    			}
    			// 控制一下遍历调度表的频率
    			select {
    			// 使用time.NewTimer创建定时器,NewTimer.C返回一个channel
    			// 当时间到了一个channel中会被放入一个Time类型的值从而唤醒阻塞,继续for遍历
    			case <- time.NewTimer(100 * time.Millisecond).C:
    			}
    		}
    	}()
    	time.Sleep(100 * time.Second)
    }
    
  • 相关阅读:
    redis应用场景之文章投票设计思路
    Redis存储的5种数据结构
    v+=e 不等价于 v=v+e
    WebMagic
    指针函数和函数指针的区别
    为什么说StringBuilder不安全?
    sql注入
    Autowired报错处理
    SpringBoot入门最简单的一个项目示例
    MVC中Cookie的用法(二)---CookieHelper
  • 原文地址:https://www.cnblogs.com/Peter2014/p/12026898.html
Copyright © 2020-2023  润新知