【Golang】Go语言中如何创建Cron定时任务

news2024/10/23 10:26:30

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

在这里插入图片描述

文章目录

  • Go语言中定时任务Cron
    • 一、Cron库的安装
    • 二、Cron库的基本用法
    • 三、Cron表达式的详解
    • 四、Cron库的高级用法
      • 1. 使用自定义的Job类型
      • 2. 动态调整任务配置
      • 3. 预定义时间格式
      • 4. 使用带参数的函数作为任务
      • 5. 定义带参数的Job类型
    • 五、总结

Go语言中定时任务Cron

Cron是一个强大的定时任务调度库,它允许开发者在Go应用中方便地设置和管理定时任务。Cron库通过解析Cron表达式,可以精确控制任务的执行时间和频率。本文将结合具体案例,详细介绍Cron在Go语言中的用法,包括安装、基本用法、Cron表达式的详解、高级用法以及实际应用案例。

一、Cron库的安装

在使用Cron库之前,需要先将其安装到Go开发环境中,项目中创建go mod文件,配置好代理。可以使用以下命令进行安装:

go get github.com/robfig/cron/v3

安装完成后,就可以在Go代码中导入Cron库并开始使用了。

二、Cron库的基本用法

Cron库的核心是使用Cron表达式来定义任务的执行时间和频率。Cron表达式由六个字段组成,分别表示秒、分、时、日、月、周几(0~6表示周日到周六)。

以下是一个简单的示例代码,展示如何使用Cron库创建一个每5秒钟执行一次的定时任务:

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

func main() {
	// 创建一个新的Cron实例,默认是支持分钟级别的调度,加上cron.WithSeconds() 支持秒级别调度
	c := cron.New(cron.WithSeconds()) //精确到秒级

	// 添加一个每5秒钟执行一次的定时任务
	spec := "*/5 * * * * *"
	// func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error)
	// AddFunc第一个参数是一个Cron表达式,表示任务的执行时间和频率;第二个参数是一个无参的函数
	c.AddFunc(spec, func() {
		fmt.Println("Task executed every 5 seconds", time.Now())
	})

	// 启动Cron实例,开始执行定时任务
	c.Start()

	// 为了演示效果,让主程序运行一段时间
	time.Sleep(30 * time.Second)

	// 停止Cron实例(在实际应用中,通常不需要手动停止Cron实例,除非程序需要退出)
	c.Stop()
}

在这里插入图片描述

在这个示例中,我们首先创建了一个Cron实例,然后使用AddFunc方法添加了一个每5秒钟执行一次的定时任务。AddFunc方法接受两个参数:第一个参数是一个Cron表达式,表示任务的执行时间和频率;第二个参数是一个无参的函数,表示要执行的任务。最后,我们调用Start方法启动Cron实例,并开始执行定时任务。为了演示效果,我们使用time.Sleep让主程序运行了一段时间,然后调用Stop方法停止了Cron实例。

三、Cron表达式的详解

Cron表达式是Cron库的核心,用于定义任务的执行时间和频率。Cron表达式由六个字段组成,每个字段用空格分隔,分别表示:

  1. 秒(0-59)
  2. 分(0-59)
  3. 时(0-23)
  4. 日(1-31)
  5. 月(1-12或JAN-DEC)
  6. 周几(0-6或SUN-SAT)

每个字段可以包含以下特殊字符:

  • *:表示匹配任何值。例如,在月份字段中使用*,表示每个月。
  • /:表示步长。例如,在小时字段中使用*/2,表示每2小时触发一次。
  • ,:列举一些离散的值和多个范围。例如,在周几字段中使用MON,WED,FRI,表示周一、三和五。
  • -:表示范围。例如,在小时字段中使用9-17,表示从上午9点到下午5点。
  • ?:只能用在日和周几字段中,用来代替*,表示每月/周的任意一天(注意:在某些Cron实现中,?可能不被支持)。

以下是一些Cron表达式的示例及其含义:

  • 30 * * * * *:表示每分钟的第30秒触发。
  • 0 0/5 * * * *:表示每5分钟的第0秒触发。
  • 0 0 1 * * *:表示每月1日的0点触发。
  • 0 0 * * 1 *:表示每周一的0点触发。
  • 0 0 * * * MON:表示每周一的0点触发(与上一个表达式等价,但使用了周几的简写)。
  • 0 0/30 9-17 * * *:表示在上午9点到下午5点之间,每30分钟触发一次。
    在这里插入图片描述

go语言定时任务cron中的*和?
在Cron表达式中,*和"?"都是用来指定时间的通配符,但它们有一些区别:

"*":星号()可以用在所有字段上,表示该字段的任何值。例如,如果你想要在每分钟的每秒钟触发任务,你可以使用"*"在秒字段上。

"?":问号(?)可以用在日和星期字段上,表示不指定值。不同于星号(*),问号不能用在其他字段上。当你在日字段上使用"?"时,意味着不关心那天是哪一天,只关心月份和星期字段。同理,在星期字段上使用"?"时,意味着不关心那天是星期几,只关心日字段和月份字段。

如果是使用 crontab := cron.New() 则只需要五个 * 。如 ***** 从分钟开始
如果使用cron.New()定义,却使用了6个* 运行将会报错
在这里插入图片描述

四、Cron库的高级用法

除了基本的AddFunc方法外,Cron库还提供了一些高级用法,如使用自定义的Job类型、动态调整任务配置、获取任务执行结果等。

1. 使用自定义的Job类型

Cron库允许使用自定义的Job类型,实现更加灵活的任务调度。以下是一个示例代码,展示如何使用自定义的Job类型:

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

// MyJob 定义一个自定义的Job类型
type MyJob struct {
	// 可以根据需要添加其他字段
}

// Run 实现cron.Job接口中的Run方法
func (j *MyJob) Run() {
	fmt.Println("MyJob is running", time.Now())
}

func main() {
	c := cron.New(cron.WithSeconds())

	// 创建一个自定义Job的实例
	myJob := &MyJob{}

	// 添加自定义Job到Cron实例中。这里使用AddJob方法
	_, err := c.AddJob("*/5 * * * * *", myJob)
	if err != nil {
		fmt.Println("Error adding job:", err)
		return
	}

	c.Start()
	time.Sleep(30 * time.Second)
	c.Stop()
}

在这里插入图片描述

在这个示例中,我们定义了一个自定义的Job类型MyJob,并实现了cron.Job接口的Run方法。然后,我们创建了一个MyJob的实例,并将其添加到Cron实例中。这样,每当Cron表达式匹配时,就会执行MyJobRun方法。

2. 动态调整任务配置

Cron库允许在运行时动态调整任务的配置。以下是一个示例代码,展示如何动态添加、删除和更新定时任务:

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

func main() {
	c := cron.New(cron.WithSeconds())

	// 添加一个每5秒钟执行一次的定时任务
	entryID, err := c.AddFunc("*/5 * * * * *", func() {
		fmt.Println("Task 1: Every 5 seconds", time.Now())
	})
	if err != nil {
		fmt.Println("Error adding task 1:", err)
		return
	}
	// 启动定时器
	c.Start()
	// 等待一段时间,以便观察任务1的执行
	time.Sleep(10 * time.Second)

	// 删除任务1
	c.Remove(entryID)

	// 添加一个每10秒钟执行一次的定时任务
	_, err = c.AddFunc("*/10 * * * * *", func() {
		fmt.Println("Task 2: Every 10 seconds", time.Now())
	})
	if err != nil {
		fmt.Println("Error adding task 2:", err)
		return
	}

	// 为了演示效果,让主程序运行一段时间
	time.Sleep(30 * time.Second)

	c.Stop()
}

在这里插入图片描述

在这个示例中,我们首先添加了一个每5秒钟执行一次的定时任务,并获取了其EntryID。然后,我们等待了一段时间,以便观察任务1的执行情况。接着,我们使用EntryID删除了任务1,并添加了一个每10秒钟执行一次的定时任务。最后,我们启动了Cron实例,并让主程序运行了一段时间以观察任务2的执行情况。

需要注意的是,在删除任务时,我们需要提供正确的EntryID。如果EntryID不正确或任务已经被删除,那么删除操作将失败并返回错误。

3. 预定义时间格式

在这里插入图片描述

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

func main() {
	// 创建一个新的Cron实例,默认是支持分钟级别的调度,加上cron.WithSeconds() 支持秒级别调度
	c := cron.New(cron.WithSeconds()) //精确到秒级

	// 添加一个每3秒钟执行一次的定时任务 也可以使用预定义时间格式
	spec := "@every 3s"
	// func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error)
	// AddFunc第一个参数是一个Cron表达式,表示任务的执行时间和频率;第二个参数是一个无参的函数
	c.AddFunc(spec, func() {
		fmt.Println("Task executed every 3 seconds", time.Now())
	})

	// 启动Cron实例,开始执行定时任务
	c.Start()

	// 为了演示效果,让主程序运行一段时间
	time.Sleep(30 * time.Second)

	// 停止Cron实例(在实际应用中,通常不需要手动停止Cron实例,除非程序需要退出)
	c.Stop()
}

在这里插入图片描述

4. 使用带参数的函数作为任务

如果我们需要在任务函数中使用参数,可以使用闭包或者定义一个带参数的函数类型。
使用闭包传递参数
闭包是一种捕获并存储其外部作用域的引用的函数。利用闭包,我们可以轻松地将参数传递给定时任务函数。

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
)

func main() {
	c := cron.New(cron.WithSeconds())

	// 定义一个带参数的外部函数 外函数带有参数,返回一个函数
	executeTask := func(param string) func() {
		return func() {
			fmt.Println("Task executed with parameter:", param)
		}
	}

	// 使用闭包传递参数
	taskParam := "Hello, Cron with Closure!"
	c.AddFunc("@every 1s", executeTask(taskParam))

	c.Start()
	// 为了让程序运行足够长的时间以观察定时任务的执行,我们使用一个空的select语句来阻塞主goroutine
	select {}
}

在这里插入图片描述
在这个示例中,我们定义了一个名为executeTask的外部函数,它接受一个字符串参数并返回一个无参数的函数(即闭包)。
在闭包内部,我们打印了传递进来的参数。然后,我们将这个闭包作为任务函数添加到Cron实例中。

5. 定义带参数的Job类型

除了使用闭包外,我们还可以定义一个带参数的Job类型。这需要实现cron.Job接口,该接口包含一个Run方法。

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

// ParamJob 定义带参数的Job类型
type ParamJob struct {
	param string
}

// Run 实现cron.Job接口的Run方法
func (j *ParamJob) Run() {
	fmt.Println("ParamJob executed with parameter:", j.param, time.Now())
}

func main() {
	c := cron.New(cron.WithSeconds())

	// 创建一个ParamJob实例并设置参数
	jobParam := "Hello, Cron with ParamJob!"
	//注意,这里定义对象的时候使用指针
	paramJob := &ParamJob{param: jobParam}

	// 将ParamJob实例添加到Cron实例中
	// 注意:由于AddJob方法期望的是一个cron.Job接口,因此我们需要将ParamJob实例的指针转换为cron.Job接口
	c.AddJob("@every 2s", paramJob)

	c.Start()
	// 使用一个空的select语句来阻塞主goroutine
	select {}
}

在这里插入图片描述

在这个示例中,我们定义了一个名为ParamJob的结构体类型,并为其添加了一个param字段来存储参数。然后,我们实现了cron.Job接口的Run方法,在该方法中打印了参数。最后,我们创建了一个ParamJob实例,并将其添加到Cron实例中。

需要注意的是,在调用AddJob方法时,我们需要将ParamJob实例的指针转换为cron.Job接口。这是因为AddJob方法期望的是一个实现了cron.Job接口的对象。

五、总结

Cron库是一个功能强大且易于使用的Go语言定时任务库。它提供了灵活的Cron表达式和易于使用的API,使开发者能够方便地添加和管理定时任务。通过本文的介绍和示例代码,我们了解了Cron库的基础用法、实际案例以及高级用法(如动态添加和移除任务、使用带参数的函数作为任务)。这些知识和技巧将帮助我们更好地在Go应用中使用Cron库来实现定时任务调度。

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

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

相关文章

MySQL【知识改变命运】11

联合查询 6. ⼦查询6.1 语法6.2 单⾏⼦查询6.3 多⾏⼦查询6.4 多列⼦查询6.5 在from⼦句中使⽤⼦查询 7. 合并查询7.1 创建新表并初始化数据7.2 Union7.3 Union all 8. 插⼊查询结果8.1 语法8.2 ⽰例 6. ⼦查询 ⼦查询是把⼀个SELECT语句的结果当做别⼀个SELECT语句的条件&…

10.22 MySQL

存储过程 存储函数 存储函数是有返回值的存储过程,存储函数的参数只能是in类型的。具体语法如下: characteristic 特性 练习: 从1到n的累加 ​​​​​​ create function fun1(n int) returns int deterministic begindeclare total i…

制氮机分子筛的作用

制氮机作为一种重要的工业设备,广泛应用于食品、饮料、化学、石油、电子和医疗保健等多个行业。其核心组件之一——分子筛。本文将详细探讨制氮机分子筛的作用及其重要性。 一、分子筛的基本概念 分子筛是一种具有均匀孔径的多孔材料,常用于气体分离和纯…

Elasticsearch 中的高效按位匹配

作者:来自 Elastic Alexander Marquardt 探索在 Elasticsearch 中编码和匹配二进制数据的六种方法,包括术语编码(我喜欢的方法)、布尔编码、稀疏位位置编码、具有精确匹配的整数编码、具有脚本按位匹配的整数编码以及使用 ESQL 进…

基于vue框架的的二手车交易系统的设计与实现thx7v(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,卖家,车辆类型,二手车,在线留言,订单信息 开题报告内容 基于Vue框架的二手车交易系统的设计与实现开题报告 一、课题背景及意义 随着汽车消费市场的日益成熟与消费者换车频率的增加,二手车交易市场逐渐成为汽车市场的…

pycharm配置git版本控制

今天记录一下如何在pycharm工具中配置git版本控制,主要分以下步骤: 1、安装git 首先需要有git环境,去git官网下载git安装包,下一步下一步执行安装完成即可 2、在pycharm中配置git路径 下载git后,在pycharm的 setti…

「AIGC」n8n AI Agent开源的工作流自动化工具

n8n AI Agent 是一个利用大型语言模型(LLMs)来设计和构建智能体(agents)的工具,这些智能体能够执行一系列复杂的任务,如理解指令、模仿类人推理,以及从用户命令中理解隐含意图。n8n AI Agent 的核心在于构建一系列提示(prompts),使 LLM 能够模拟自主行为。 传送门→ …

GAMES104:17 游戏引擎的玩法系统:高级AI-学习笔记

文章目录 课前QA一,层次任务网络(Hierarchical Tasks Network,HTN)1.1 HTN Framework1.2 HTN Task Types1.2.1 Primitive Task基本任务1.2.2 Compound Task符合任务 1.3 Planning1.4 Replan1.5 总结 二,目标导向行为规…

在ECS实例上搭建WordPress博客平台

WordPress是使用PHP语言开发的博客平台,在支持PHP和MySQL数据库的服务器上,您可以用WordPress搭建自己的网站,也可以用作内容管理系统(CMS)。本教程介绍如何在不同操作系统的ECS实例上,手动搭建WordPress网…

SonarQube快速实践

SonarQube快速实践 1. 简介 SonarQube 是一个本地部署的代码分析工具,旨在检测30多种编程语言、框架和基础设施即代码(IaC)平台中的代码问题。通过直接集成到您的持续集成(CI)流水线中或在我们支持的DevOps平台之一上…

转行AI产品经理,第二步怎么走

之前写了一篇文章《转行AI产品经理,第一步怎么走》,好多小伙伴私信我,和我聊了一些细节,我感觉有必要再聊一聊,转行AI产品经理,第二步怎么走。 在上一篇文章里我们聊了一个小糖人游戏,从而得出…

用AI怎样来迭代优秀的学习法,AI+费曼学习法的妙用!

大家好,我是Shelly,一个专注于输出AI工具和科技前沿内容的AI应用教练,体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具,拥抱AI时代的到来。 AI工具集1:大厂AI工具【共23款…

Quartus Ⅱ仿真 2.三人表决电路

奥里给,一起加油啊,我会陪着你们的! 仿真波形: 输出结果: 介绍: 三人表决电路是一种数字逻辑电路,用于实现三个输入信号的多数表决。在这种电路中,如果至少有两个输入为高电平&a…

MySQL-事物隔离级别

1. MySQL事物的四种隔离级别 1.1 读未提交(READ UNCOMMITTED) READ UNCOMMITED提供了事物之间最小限度的隔离,除了幻读和不可重复读取的操作外,处于这个隔离级别的事务可以读到其它事务还未提交的数据。 1.2 读已提交&#xf…

利用 Direct3D 绘制几何体—7.编译着色器

在 Direct3D 中,着色器程序必须先被编译为一种可移植的字节码。接下来,图形驱动程序将获取这些字节码,并将其重新编译为针对当前系统 GPU 所优化的本地指令 [ATI1]。我们可以在运行期间用下列函数对着色器进行编译。 HRESULT D3DCompileFrom…

创建型模式-----(单例模式)

目录 基本概念 饿汉式: 懒汉式: 上锁双判空版本 std::call_once版本: C11标准后局部静态变量版本: 项目中单例模板的应用 基本概念 单例模式:在程序运行期间只有一份,与程序生存周期一样,…

对比学习论文随笔 1:正负样本对(Contrastive Learning 基础论文篇)

为了阅读的流畅,当前针对相同的代理任务按时间顺序进行梳理,涉及仅使用正负样本思想且优化目标一致的「基础」论文(2018-2020),编码器均采用 ResNet。 文章目录 前言对比学习和代理任务(Pretext task&#…

浪潮云启操作系统(InLinux)bcache缓存实践:理解OpenStack环境下虚拟机卷、Ceph OSD、bcache设备之间的映射关系

前言 在OpenStack平台上,采用bcache加速ceph分布式存储的方案被广泛用于企业和云环境。一方面,Ceph作为分布式存储系统,与虚拟机存储卷紧密结合,可以提供高可用和高性能的存储服务。另一方面,bcache作为混合存储方案&…

Java笔试06

在Java中,异常可以分为两大类:编译时异常(编译时检查异常)和运行时异常(非编译时检查异常)。 编译时异常(Checked Exceptions)是指在编译时期必须被捕获或声明抛出的异常。这些异常…

字节流写入文件

一、创建输出流对象表示的文件三种方式 方法一: FileOutputStream fos new FileOutputStream("fos.txt",true);//最简便方法二: FileOutputStream fos new FileOutputStream(new File("fos.txt"));方法三; File f ne…