golang 定时器

上网查了下相关资料,基本上都介绍的是github.com\robfig\cron这个包来执行定时任务,试了下确实可以执行。但是此包下没有删 除任务的方法,只有暂停的方法(Stop),若要停止之前的任务只执行新定义的任务,除非服务器重启再定义新任务。后来又参考了一下其他人的建议,采用了 github.com\jakecoffman\cron这个包。后者是在前者的基础上做了一定的修改,给每个任务添加的一个新属性Name,然后新添加 一个remove(name)方法,用来删除指定名字的任务,经测试使用后可正常删除任务,只不过之前的计划任务名得新建一个全局变量来存储。

以下先简单介绍下定义时间集合的信息:

字段名 是否必须 允许的值 允许的特定字符
秒(Seconds) 0-59
* / , -
分(Minutes) 0-59
* / , -
时(Hours) 0-23
* / , -
日(Day of month) 1-31
* / , – ?
月(Month) 1-12 or JAN-DEC
* / , -
星期(Day of week) 0-6 or SUM-SAT
* / , – ?

注:
1)月(Month)和星期(Day of week)字段的值不区分大小写,如:SUN、Sun 和 sun 是一样的。
2)星期
(Day of week)字段如果没提供,相当于是 *

2、特殊字符说明
1)星号(*)
表示 cron 表达式能匹配该字段的所有值。如在第5个字段使用星号(month),表示每个月

回到顶部
2)斜线(/)
表示增长间隔,如第1个字段(minutes) 值是 3-59/15,表示每小时的第3分钟开始执行一次,之后每隔 15 分钟执行一次(即 3、18、33、48 这些时间点执行),这里也可以表示为:3/15

回到顶部
3)逗号(,)
用于枚举值,如第6个字段值是 MON,WED,FRI,表示 星期一、三、五 执行

回到顶部
4)连字号(-)
表示一个范围,如第3个字段的值为 9-17 表示 9am 到 5pm 直接每个小时(包括9和17)

回到顶部
5)问号(?)
只用于 日(Day of month) 和 星期(Day of week),表示不指定值,可以用于代替 *

在beego下使用,我简单的封装一下(代码不是我写的,而且写的很随意,也只保证了可用的程度),自定义package jobs如下:

job.go源码:

[plain] view plain copy

  1. package jobs
  2. import (
  3. "github.com/astaxie/beego"
  4. "github.com/jakecoffman/cron"
  5. "reflect"
  6. "runtime/debug"
  7. "sync"
  8. "sync/atomic"
  9. )
  10. type Job struct {
  11. Name    string
  12. inner   cron.Job
  13. status  uint32
  14. running sync.Mutex
  15. }
  16. const UNNAMED = "(unnamed)"
  17. func New(job cron.Job) *Job {
  18. name := reflect.TypeOf(job).Name()
  19. if name == "Func" {
  20. name = UNNAMED
  21. }
  22. return &Job{
  23. Name:  name,
  24. inner: job,
  25. }
  26. }
  27. func (j *Job) Status() string {
  28. if atomic.LoadUint32(&j.status) > 0 {
  29. return "RUNNING"
  30. }
  31. return "IDLE"
  32. }
  33. func (j *Job) Run() {
  34. // If the job panics, just print a stack trace.
  35. // Don‘t let the whole process die.
  36. defer func() {
  37. if err := recover(); err != nil {
  38. beego.Error("%v", debug.Stack())
  39. }
  40. }()
  41. if !selfConcurrent {
  42. j.running.Lock()
  43. defer j.running.Unlock()
  44. }
  45. if workPermits != nil {
  46. workPermits <- struct{}{}
  47. defer func() { <-workPermits }()
  48. }
  49. atomic.StoreUint32(&j.status, 1)
  50. defer atomic.StoreUint32(&j.status, 0)
  51. j.inner.Run()
  52. }

jobrunner.go源码:

[plain] view plain copy

  1. // A job runner for executing scheduled or ad-hoc tasks asynchronously from HTTP requests.
  2. //
  3. // It adds a couple of features on top of the cron package to make it play nicely with Revel:
  4. // 1. Protection against job panics.  (They print to ERROR instead of take down the process)
  5. // 2. (Optional) Limit on the number of jobs that may run simulatenously, to
  6. //    limit resource consumption.
  7. // 3. (Optional) Protection against multiple instances of a single job running
  8. //    concurrently.  If one execution runs into the next, the next will be queued.
  9. // 4. Cron expressions may be defined in app.conf and are reusable across jobs.
  10. // 5. Job status reporting.
  11. package jobs
  12. import (
  13. //"fmt"
  14. "github.com/jakecoffman/cron"
  15. "time"
  16. )
  17. // Callers can use jobs.Func to wrap a raw func.
  18. // (Copying the type to this package makes it more visible)
  19. //
  20. // For example:
  21. //    jobs.Schedule("cron.frequent", jobs.Func(myFunc))
  22. type Func func()
  23. func (r Func) Run() { r() }
  24. //定时执行任务
  25. func Schedule(spec string, job cron.Job, name string) error {
  26. sched := cron.Parse(spec)
  27. /*if err != nil {
  28. return err
  29. }*/
  30. MainCron.Schedule(sched, New(job), name)
  31. return nil
  32. }
  33. // Run the given job at a fixed interval.
  34. // The interval provided is the time between the job ending and the job being run again.
  35. // The time that the job takes to run is not included in the interval.
  36. func Every(duration time.Duration, job cron.Job, name string) {
  37. MainCron.Schedule(cron.Every(duration), New(job), name)
  38. }
  39. // Run the given job right now.
  40. func Now(job cron.Job) {
  41. go New(job).Run()
  42. }
  43. // Run the given job once, after the given delay.
  44. func In(duration time.Duration, job cron.Job) {
  45. go func() {
  46. time.Sleep(duration)
  47. New(job).Run()
  48. }()
  49. }
  50. // 暂停所有任务
  51. func Stop() {
  52. MainCron.Stop()
  53. }
  54. //清空任务
  55. func Remove(name string) {
  56. MainCron.RemoveJob(name)
  57. }

plugin.go源码:

[plain] view plain copy

  1. package jobs
  2. import (
  3. "github.com/jakecoffman/cron"
  4. )
  5. const DEFAULT_JOB_POOL_SIZE = 10
  6. var (
  7. // Singleton instance of the underlying job scheduler.
  8. MainCron *cron.Cron
  9. // This limits the number of jobs allowed to run concurrently.
  10. workPermits chan struct{}
  11. // Is a single job allowed to run concurrently with itself?
  12. selfConcurrent bool
  13. )
  14. func init() {
  15. MainCron = cron.New()
  16. workPermits = make(chan struct{}, DEFAULT_JOB_POOL_SIZE)
  17. selfConcurrent = false
  18. MainCron.Start()
  19. }

因为是网站执行定时任务,这边我是将任务是否开启的控制权放在前端页面,通过点击按钮访问controller方法,从而启动任务,所以我把任务执行方法放在了controller中。通过如下方式调用:

[plain] view plain copy

  1. import (
  2. //其他引用包我都省略了
  3. "hnnaserver/src/jobs"
  4. )
  5. type job struct {
  6. user     string
  7. province int64
  8. method   int64
  9. count    int64
  10. }
  11. //任务执行的方法
  12. func (j *job) Run() {
  13. //do something....
  14. }
  15. func (this *SystemController) AutoDisCus() {
  16. spec := "0 0 15 * * 1-5"//定义执行时间点 参照上面的说明可知 执行时间为 周一至周五每天15:00:00执行
  17. //spec := "*/5 * * * * ?" //这是网上一般的例子 即每5s执行一次
  18. j := &job{user, province, method, count}
  19. jobs.Schedule(spec, j, taskName) //3个参数分别为 执行时间(规则之间介绍过) 要执行的任务  任务名
  20. }

若要删除某项任务,则调用remove方法即可,如下:

[plain] view plain copy

    1. jobs.Remove(tasksName)
时间: 2024-09-30 04:31:48

golang 定时器的相关文章

一周学会go语言并应用 by王奇疏

<一周学会go语言并应用> by王奇疏 ( 欢迎加入go语言群: 218160862 , 群内有实践) 零.安装go语言,配置环境及IDE 这部分内容不多,请参考我的这篇安装环境<安装go语言,配置环境及IDE> 日常只有2条命令: go   run  文件路径/xxx.go go   build  文件路径/xxx.go 第一节.语法 1)注释:   // 单行注释      /* 多行注释 *// 2). [基本语法] 一个go语言程序项目只能有1个 package main包

Golang中使用heap编写一个简单高效的定时器模块

定时器模块在服务端开发中非常重要,一个高性能的定时器模块能够大幅度提升引擎的运行效率.使用Golang和heap实现一个通用的定时器模块,代码来自:https://github.com/xiaonanln/goTimer 也可以查看文档:http://godoc.org/github.com/xiaonanln/goTimer,下面是完整的代码,并进行适当的注释和分析. 从性能测试结果来看,基于heap的定时器模块在效率上并不会比时间轮(TimeWheel)的实现慢多少,但是逻辑上要简单很多.

golang 高效低精度定时器实现

golang默认定时器是通过time模块提供的,不管是golang,libev,libevent也好,定时器都是通过最小堆实现的,导致加入定时器时间复杂度为O(lgn),在需要大量定时器时效率较低,所以Linux提供了基于时间轮的实现,我们本次提供的 定时器实现就是标准的Linux时间轮实现方式.当然,我是把Skynet(https://github.com/cloudwu/skynet/blob/master/skynet-src/skynet_timer.c)的定时器移植了过来,偷窃无罪..

Golang 完成一个 Crontab定时器(1)

前言 Linux的Crontab定时器似乎已经足够强大,但是我认为还是没有办法满足我们所有的需求,例如定时器某一瞬间需要动态添加/删除任务的功能,例如定时器只能在指定的节点上启动(主节点),其他节点不需要定时服务,这种情况Linux自带的Crontab就不能够满足我们的需求了,所以这次要徒手定义一个Crontab定时器,作为自己的备用. 需求分析 看我博客的基本也都知道,做任何事,都要进行一个需求分析.既然是一个定时器,那么应该支持的功能如下 定时启动任务(废话) 支持基础的Crontab语法

一个信号量与定时器的例子(Golang)

程序可用来定时执行一些任务,并通过信号量处理,在被强制中断时,也能做相应警告及清理处理. package main //信号量与定时器 //author: Xiong Chuan Liang //date: 2015-2-25 import "fmt" import "os" import "os/signal" import "time" func main() { sigs := make(chan os.Signal,

golang 中的定时器(timer),更巧妙的处理timeout

今天看到kite项目中的一段代码,发现挺有意思的. // generateToken returns a JWT token string. Please see the URL for details: // http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1 func generateToken(aud, username, issuer, privateKey string) (string,

golang中timer定时器实现原理

一般我们导入import ("time")包,然后调用time.NewTicker(1 * time.Second) 实现一个定时器: func timer1() { timer1 := time.NewTicker(1 * time.Second) for { select { case <-timer1.C: xxx() //执行我们想要的操作 } } } 再看看timer包中NewTicker的具体实现: func NewTicker(d Duration) *Ticker

golang的Timer定时器

// code_047_Timer project main.go package main import ( "fmt" "time" ) func main() { timer1 := time.NewTimer(time.Second * 2) t1 := time.Now() fmt.Printf("t1:%v\n", t1) t2 := <-timer1.C fmt.Printf("t2:%v\n", t2)

golang的定时器简单使用

ticker.go package main import ( "time" "fmt" ) func main() { StartTimer() } func StartTimer() { t := time.NewTicker(time.Second * 1) for { <-t.C; //Do something fmt.Println(time.Now()) } }