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.xdnf.cn/news/146959.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

C语言编译与链接过程详解

C语言编译与链接过程详解 源文件 main.c #include <stdio.h>extern int data; extern int add(int a,int b);int a1; int a2 0; int a3 10;static int b1; static int b2 0; static int b3 20;int main() {int c1;int c2 0;int c3 30;static int d1;static int …

1004. 最大连续1的个数III(滑动窗口)

一、题目 1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public:int longestOnes(vector<int>& nums, int k) {int mark0;//标记0的个数int MaxLength0;for(int left0,right0;right<nums.size();right){if(nums…

Leetcode.965 单值二叉树

本专栏内容为&#xff1a;leetcode刷题专栏&#xff0c;记录了leetcode热门题目以及重难点题目的详细记录 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;八大排序汇总 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &…

网络运营对职业发展有什么用

大家好&#xff0c;我是网络工程师成长日记实验室的郑老师&#xff0c;您现在正在查看的是网络工程师成长日记专栏&#xff0c;记录网络工程师日常生活的点点滴滴 有个哥们联系我&#xff0c;他说他以前是做it售前&#xff0c;也做过售后&#xff0c;也做it很长时间了&#xff…

一文带你掌握 优先级队列

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

(ubuntu)Docker 安装linux 详情过程

文章目录 前言Docker 安装linux第一步&#xff1a;使用dokcker 拉取镜像&#xff1a;第二步&#xff1a;创建本地目录&#xff08;用于挂载&#xff09;第三步&#xff1a;&#xff08;上传配置文件&#xff09;修改配置文件第四步&#xff1a;创建docker容器第五步: 测试本地连…

JavaSE | 初识Java(一) | JDK \ JRE \ JVM

Java初识 Java 是一门半编译型、半解释型语言。先通过 javac 编译程序把源文件进行编译&#xff0c;编译后生成的 .class 文件是由字节 码组成的平台无关、面向 JVM 的文件。最后启动 java 虚拟机 来运行 .class 文件&#xff0c;此时 JVM 会将字节码转换成平台能够理…

docker-compose 网络配置- IP 主机名 hosts配置

docker-compose 配置IP、hostname、hosts配置 配置IP version: "3" networks:bd-network: # 声明网络external: true services:kafka: # 服务名称networks:bd-network: # 连接的网络名称ipv4_address: 172.2.0.102 # 配置IP配置 主机名 version: "3&quo…

python之股票财务分析

#import akshare as ak import pandas as pd import matplotlib.pyplot as plt symbol1"资产负债表" symbol2"利润表" symbol3"现金流量表" #df1ak.stock_financial_report_sina(stock"601633",symbolsymbol1) #df2ak.stock_financial…

检测防火墙是否开启、判断程序是否加入防火墙白名单(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

车牌超分辨率:License Plate Super-Resolution Using Diffusion Models

论文作者&#xff1a;Sawsan AlHalawani,Bilel Benjdira,Adel Ammar,Anis Koubaa,Anas M. Ali 作者单位&#xff1a;Prince Sultan University 论文链接&#xff1a;http://arxiv.org/abs/2309.12506v1 内容简介&#xff1a; 1&#xff09;方向&#xff1a;图像超分辨率技术…

Java栈的压入、弹出序列(详解)

目录 1.题目描述 2.题解 方法1 方法2 1.题目描述 输入两个整数序列&#xff0c;第一个序列表示栈的压入顺序&#xff0c;请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序&#xff0c;序列4,5,3,2,1是该压栈序…

凉鞋的 Unity 笔记 104. 测试所涉及的窗口

104. 测试所涉及的窗口 在上一篇&#xff0c;笔者简单介绍了检视器窗口&#xff0c;如图所示&#xff1a; 我们接着介绍上图中的最后一个部分内容&#xff0c;测试部分。 测试部分我们只做了一件非常简单的操作&#xff0c;就是点击了一下运行按钮&#xff0c;查看结果&#…

行为型设计模式——责任链模式

摘要 责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。 一、责任链模式意图 职责链模式&#xff08;Chain Of Responsibility&#xff09; 是一种行为设…

c语言练习73:统计位数为偶数的数字

统计位数为偶数的数字 给你⼀个整数数组 nums &#xff0c;请你返回其中位数为 偶数 的数字的个数。 • ⽰例 1&#xff1a; 输⼊&#xff1a;nums [12,345,2,6,7896] 输出&#xff1a;2 解释&#xff1a; 12 是 2 位数字&#xff08;位数为偶数&#xff09; 345 是 3 位…

Python 数据分析与挖掘(一)

Python 数据分析与挖掘&#xff08;数据探索&#xff09; 数据探索 1.1 需要掌握的工具&#xff08;库&#xff09; 1.1.1 Nump库 Numpy 提供多维数组对象和各种派生对象&#xff08;类矩阵&#xff09;&#xff0c;利用应用程序接口可以实现大量且繁琐的数据运算。可以构建…

【Java 进阶篇】MySQL 多表查询详解

MySQL 是一个强大的关系型数据库管理系统&#xff0c;多表查询是数据库操作中的重要部分之一。多表查询允许您从多个表中检索和操作数据&#xff0c;以满足复杂的数据需求。本文将介绍 MySQL 多表查询的基本概念、语法和示例&#xff0c;以及一些常见的多表查询场景。 什么是多…

SpringCloud篇

SpringCloud五大组件是啥&#xff1f; rabbin gateway feign 注册中心&#xff08;nacos,Eureka&#xff09;,服务保护 &#xff08;sentinel&#xff09; &#xff1b; nacos和eureka的区别是什么&#xff1f; 负载均衡是如何实现的&#xff1f;&#xff1f; ribbon负载策略…

【数据结构】排序之插入排序和选择排序

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;数据结构 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、排序的概念及其分类 &#x1f4d2;1.1排序的概念 &#x1f4d2;1.2排序…

朝气蓬勃 后生可畏

介绍: 线段树是一棵二叉搜索树,思想与分治很想,把一段区间平分平分再平分,平分到不能平分为止,可以进行方便的区间修改和区间查询,当然,树状数组能做的单点修改、单点查询,线段树也可以更好地实现,总之,线段树是树状数组的升级版,此外,线段树能做的平衡树也能做,但…