Go: 关于定时任务

文章目录

  • 写在前面
  • 内容
    • 基础库
      • for + sleep
      • Ticker
    • 第三方库
      • cron
        • 安装
        • @表达式
        • linux cron 表达式
        • job
        • schedule
  • 参考

写在前面

记录 Go 的一些关于定时任务的处理

内容

基础库

for + sleep

func main() {for {time.Sleep(5 * time.Second)fmt.Println("every 5s")}
}

Ticker

func main() {ticker := time.NewTicker(5 * time.Second)for range ticker.C {fmt.Println("every 5s")}
}

第三方库

cron

前面两个都是基础库里的东西,可以实现一些基本的定时功能,但对于一些稍显复杂的定时任务需求,就需要我们自己去做更多的内容来支持,比如说需求需要在每个月的 1 号,或是每周一之类的来进行任务,就需要我们自己去写代码来判断了。而 cron 这个第三方库,则能很好地支撑我们这类的需求。

安装
go get github.com/robfig/cron/v3@v3.0.0

cron 对于定时的设置有几种写法,都能达到同样的目的。

@表达式
func descriptors() {c := cron.New()// @every// 支持秒级别,会在启动 6s 后执行_, errEveryS := c.AddFunc("@every 6s", func() {fmt.Println("every 6s")})if errEveryS != nil {fmt.Printf("errEveryS: %v\n", errEveryS)}// 0.1 min = 6s_, errEveryM := c.AddFunc("@every 0.1m", func() {fmt.Println("every 0.1m")})if errEveryM != nil {fmt.Printf("errEveryM: %v\n", errEveryM)}// @yearly @annually 每年执行一次,即 1 月 1 日的时候开始执行_, errYearly := c.AddFunc("@yearly", func() {fmt.Println("yearly")})if errYearly != nil {fmt.Printf("errYearly: %v\n", errYearly)}_, errAnnually := c.AddFunc("@annually", func() {fmt.Println("annually")})if errAnnually != nil {fmt.Printf("errAnnually: %v\n", errAnnually)}// @monthly 每个月的第一天的零点执行_, errMonthly := c.AddFunc("@monthly", func() {fmt.Println("monthly")})if errMonthly != nil {fmt.Printf("errMonthly: %v\n", errMonthly)}// @weekly 每周的第一天零点执行,这个第一天可能是周六,也可能是周日_, errWeekly := c.AddFunc("@weekly", func() {fmt.Println("weekly")})if errWeekly != nil {fmt.Printf("errWeekly: %v\n", errWeekly)}// @hourly 每小时执行一次,启动后一小时执行_, errHourly := c.AddFunc("@hourly", func() {fmt.Println("hourly")})if errHourly != nil {fmt.Printf("errHourly: %v\n", errHourly)}// @daily @midnight,每天执行一次,在每天的零点执行_, errDaily := c.AddFunc("@daily", func() {fmt.Println("daily")})if errDaily != nil {fmt.Printf("errDaily: %v\n", errDaily)}_, errMidnight := c.AddFunc("@midnight", func() {fmt.Println("midnight")})if errMidnight != nil {fmt.Printf("errMidnight: %v\n", errMidnight)}c.Start()defer c.Stop()select {}
}
linux cron 表达式

如果我们想要更灵活的一些处理,就需要学习下 Linux 的 cron 表达式,参照如下:

    *    *    *    *    *-    -    -    -    -|    |    |    |    ||    |    |    |    +----- day of week (0 - 7) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat|    |    |    +---------- month (1 - 12) OR jan,feb,mar,apr ...|    |    +--------------- day of month (1 - 31)|    +-------------------- hour (0 - 23)+------------------------- minute (0 - 59)

只要我们学会了 Linux 的 cron 表达式的使用,也就可以直接用在 cron 库上,我们可以看到 Linux cron 表达式的标准实现里,最小的时间单位是支持到分钟级别,秒级别的话我们可以用上面的方案处理。

func linux() {c := cron.New()// 每1分钟执行,等同于 */1 * * * * 和 @every 1m_, err := c.AddFunc("* * * * *", func() {fmt.Println("* * * * *")})if err != nil {fmt.Printf("err: %v\n", err)}// 每 5 分钟执行,等同于 @every 5m// / 表示频率_, err1 := c.AddFunc("*/5 * * * *", func() {fmt.Println("* * * * *")})if err1 != nil {fmt.Printf("err1: %v\n", err1)}// 每个小时的 01 分执行_, err2 := c.AddFunc("1 * * * *", func() {fmt.Println("1 * * * *")})if err2 != nil {fmt.Printf("err2: %v\n", err2)}// 每个月的第一天的 0 点 0 分运行,相当于 @monthly_, err3 := c.AddFunc("0 0 1 * *", func() {fmt.Println("0 0 1 * *")})if err3 != nil {fmt.Printf("err3: %v\n", err3)}// 每周的第一天(周六或周日)的 0 点 0 分运行,相当于 @weekly// 像一些发奖需求,在每周一进行发奖,就可以写成 0 0 * * 1_, err4 := c.AddFunc("0 0 * * 0", func() {fmt.Println("0 0 * * 0")})if err4 != nil {fmt.Printf("err4: %v\n", err4)}// 每天的 0 点 0 分运行一次,相当于 @daily 和 @midnight_, err5 := c.AddFunc("0 0 * * *", func() {fmt.Println("0 0 * * *")})if err5 != nil {fmt.Printf("err5: %v\n", err5)}// 每年运行一次,在 1 月 1 日 0 点 0 分,相当于 @yearly @annually_, err6 := c.AddFunc("0 0 1 1 *", func() {fmt.Println("0 0 1 1 *")})if err6 != nil {fmt.Printf("err6: %v\n", err6)}// 每小时运行一次,相当于 @hourly_, err7 := c.AddFunc("0 * * * *", func() {fmt.Println("0 * * * *")})if err7 != nil {fmt.Printf("err7: %v\n", err7)}// - 表示范围 , 表示列表// 这里的意思是,在每天的 3 点到 6 点和 20 点到 23 点这两个范围内,每个 30 分执行一次// 也就是 3 点 30,4 点 30,5 点 30 这样_, err8 := c.AddFunc("30 3-6,20-23 * * *", func() {fmt.Println("30 3-6,20-23 * * *")})if err8 != nil {fmt.Printf("err8: %v\n", err8)}c.Start()defer c.Stop()select {}
}

更进一步的,假如我们在做海外的应用,有时需要根据时区来进行定时任务,那么可以这么写:

func timezone() {c := cron.New()// 在东京时区,每天的 4 点 30 分运行_, err := c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() {fmt.Println("CRON_TZ=Asia/Tokyo 30 04 * * *")})if err != nil {fmt.Printf("err: %v\n", err)}c.Start()defer c.Stop()// 或者在 cron 初始化的时候指定时区tc, _ := time.LoadLocation("Asia/Tokyo")c1 := cron.New(cron.WithLocation(tc))_, err1 := c1.AddFunc("30 04 * * *", func() {fmt.Println("30 04 * * *")})if err1 != nil {fmt.Printf("err1: %v\n", err1)}c1.Start()defer c1.Stop()select {}
}
job

在工作中,为了做到封装的效果,我们可以实现 Job 接口,把任务给封装起来:

func job() {c := cron.New()j1 := MyJob{name: "1"}_, errJob1 := c.AddJob("@every 5s", &j1)if errJob1 != nil {fmt.Printf("errJob1: %v", errJob1)}j2 := MyJob{name: "2"}_, errJob2 := c.AddJob("@every 6s", &j2)if errJob2 != nil {fmt.Printf("errJob2: %v", errJob2)}c.Start()select {}
}// MyJob 对定时任务进行包装
type MyJob struct {name string
}// Run 实现 Job 接口里的 Run 方法
func (j *MyJob) Run() {fmt.Printf("myjob : %s\n", j.name)
}
schedule

如果我们想动态的调整任务的下一次运行的时间,就可以通过实现 Schedule 接口来处理:

func schedule() {c := cron.New()// 为了方便,这里用 FuncJob,就不去创建 Job 结构体了 c.Schedule(&MySchedule{}, cron.FuncJob(func() {fmt.Println("hello")}))c.Start()select {}}type MySchedule struct {
}// Next 实现 Schedule 接口的 Next 方法
// Start 的时候,会触发 Next 方法,我们可以在这个的基础上,返回下一次的运行时间
// 之后每次触发都会调用 Next,我们就可以在这里做文章,动态修改下一次的触发时间
func (s *MySchedule) Next(t time.Time) time.Time {fmt.Printf("now time: %v\n", t)result := t.Add(5 * time.Second)return result
}

参考

crontab执行时间计算
cron github

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/93573.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Docker部署ElasticSearch7+ELK(附带ES操作操作命令集)

ElasticSearch 7ELK 程序安装Docker安装下载ES镜像提前创建挂载文件夹添加配置文件创建并启动容器可能出现的异常安装IK分词使用ElasticHD客户端工具(目前使用发现无法做增删改)安装Kibana 软件包安装安装ElasticSearch(需要JDK1.8)安装IK(下…

TS系列之typeof

TS系列之typeof 这里写目录标题 前言回顾:Js中typeof的用法1、typeof的返回类型有哪些 Ts 中的 typeof 运算符作为类型判断的工具什么是 typeof?类型保护与条件类型复杂类型 总结 前言 今天总结一下typeof相关的知识。 typeof在Js中也是常用来判断变量…

来看看双阶段目标检测算法趴

🚀 作者 :“码上有钱” 🚀 文章简介 :AI-目标检测算法 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬简介 双阶段目标检测算法是一类深度学习算法,通常分为两个阶段来检测和识别图像中的…

【时区】Flink JDBC 和CDC时间字段时区 测试及时间基准

关联文章: 各种时间类型和timezone关系浅析 一、测试目的和值 1. 测试一般的数据库不含time zone的类型的时区。 mysql timestamp(3) 类型postgres timestamp(3) 类型sqlserver datetime2(3) 类型oracle类型 TIMESTAMP(3) 类型 在以下测试之中均为ts字段 2.测试CDC中元数据…

【数据结构】堆的应用-----TopK问题

目录 一、前言 二、Top-k问题 💦解法一:暴力排序 💦解法二:建立N个数的堆 💦解法三:建立K个数的堆(最优解) 三、完整代码和视图 四、共勉 一、前言 在之前的文章中&#xff…

【Kubernetes】当K8s出现问题时,我们可以从哪些方面排查出

前言 kubernetes,简称K8s,是用8代替名字中间的8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kub…

python中dir()和help()的作用

在 Python 中,dir() 和 help() 是两个常用的内置函数,用于获取对象的属性和方法信息以及提供帮助文档。 dir(object) 函数返回一个包含对象 object 的属性和方法名称的列表。如果没有提供参数,则返回当前作用域内的所有名称。例如&#xff0…

善于拆约束条件+合并相关项+DS维护:0928T2

http://cplusoj.com/d/senior/p/SS230928B 老套路了 考虑枚举0和2 m j m i n ( f a m − g a j , f b m − g b j ) \large mjmin(fa_m-ga_j,fb_m-gb_j) mjmin(fam​−gaj​,fbm​−gbj​) 然后拆一下min,再分情况讨论一下,移项合并相同的 以其中一…

DAMA-DMBOK2重点知识整理CDGA/CDGP——第14章 大数据与数据科学

目录 一、分值分布 二、重点知识梳理 1、引言 1.1 业务驱动因素 1.2 原则 1.3 基本理念 2、活动 2.1 定义大数据战略和业务需求 2.2 选择数据源 2.3 获得和接收数据源 2.4 制定数据假设和方法 2.5 集成和调整数据进行分析 2.6 使用模型探索数据 2.7 部署和监控 …

Linux CentOS7 vim多文件与多窗口操作

窗口是可视化的分割区域。Windows中窗口的概念与linux中基本相同。连接xshell就是在Windows中新建一个窗口。而vim打开一个文件默认创建一个窗口。同时,Vim打开一个文件也就会建立一个缓冲区,打开多个文件就会创建多个缓冲区。 本文讨论vim中打开多个文…

[Java框架] Java常用爬虫框架推荐

Selenium GitHub 截止 2023年9月份 Star数量27.7K Selenium是一款基于浏览器自动化的工具,它可以模拟用户在浏览器上的操作行为,并获取网页上的内容。Selenium支持多种浏览器,可以很好地处理JavaScript生成内容。但是Selenium相较于其他框架而…

【单片机】14-I2C通信之EEPROM

1.EEPROM概念 1.EEPROM 1.1 一些概念 (1)一些概念:ROM【只读存储器---硬盘】,RAM【随机访问存储器--内存】,PROM【可编程的ROM】,EPROM【可擦除ROM】,EEPROM【电可擦除ROM】 1.2 为什么需要EE…

应用大五人格测试,来做个人职业规划

应用大五人格测试做职业规划,一方面能让大学生清楚知晓自己的性格特征,置身适合怎样的职业,让他们结合自己的兴趣爱好职业走向,进一步了解自己适合做的职业规划。另一方面可以帮助他们结合职业规划来安排人生,一步一个…

Transformer学习-self-attention

这里写自定义目录标题 Self-attentionMulti-head self-attention用self-attention解决其他问题 Self-attention 用Wq、Wk、Wv分别乘输入向量得到q、k、v向量 用每个q向量乘所有的k向量得到对应项的attention,即用每项的query向量去匹配所有的key向量,得…

【进阶C语言】自定义类型

本节内容大致目录如下: 1.结构体 2.位段 3.枚举 4.联合(共用体) 以上都是C语言中的自定义类型,可以根据我们的需要去定义。 一、结构体 一些基础知识在初阶C语言的时候已经介绍过,在这里粗略概括;重…

代码随想录算法训练营第五十五天 | 动态规划 part 12 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

目录 300.最长递增子序列思路代码 674. 最长连续递增序列思路代码 718. 最长重复子数组思路代码 300.最长递增子序列 Leetcode 思路 dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度递推公式:if (nums[i] > nums[j]) dp[i] max(dp[i], dp[j] 1)初…

面试总结之Spring篇

一、AOP 1、什么是AOP 1.1、概述 AOP(Aspect-Oriented Programming):面向切面编程,即把一些业务逻辑中的相同代码抽取出来,让业务逻辑更加简练清爽 如果要CRUD写一堆业务,可如何实现业务代码前后进行打印…

计算机竞赛 深度学习驾驶行为状态检测系统(疲劳 抽烟 喝水 玩手机) - opencv python

文章目录 1 前言1 课题背景2 相关技术2.1 Dlib人脸识别库2.2 疲劳检测算法2.3 YOLOV5算法 3 效果展示3.1 眨眼3.2 打哈欠3.3 使用手机检测3.4 抽烟检测3.5 喝水检测 4 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于深度学习的驾…

WebSocket的那些事(6- RabbitMQ STOMP目的地详解)

目录 一、目的地类型二、Exchange类型目的地三、Queue类型目的地四、AMQ Queue类型目的地五、Topic类型目的地 一、目的地类型 在上节 WebSocket的那些事(5-Spring STOMP支持之连接外部消息代理)中我们已经简单介绍了各种目的地类型,如下图&…

【强化算法专题一】双指针算法

【强化算法专题一】双指针算法 1.双指针算法--移动零2.双指针算法--复写零3.双指针算法--快乐数4.双指针算法--盛水最多的容器5.双指针算法--有效三角形的个数6.双指针算法--和为s的两个数7.双指针算法--三数之和8.双指针算法--四数之和 1.双指针算法–移动零 算法原理解析----…