内容简介:cron表达式,主要用于定时作业(定时任务)系统定义执行时间或执行频率的表达式。Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:从右边看,就是年+周几+月日时分秒
一、cron表达式
cron表达式,主要用于定时作业(定时任务)系统定义执行时间或执行频率的表达式。Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
Seconds Minutes Hours DayofMonth Month DayofWeek Year或 Seconds Minutes Hours DayofMonth Month DayofWeek
从右边看,就是年+周几+月日时分秒
1.例子
0 0 3 * * ? 每天3点执行 0 5/10 3 * * ? 0 10 3 ? * 1 */5 * * * * ? 0 */1 * * * ? 0 0/3 * * * ? 0 0/5 14 * * ? 0 0 5-15 * * ? 0 0 10,14,16 * * ? 0 10 3 ? * 1#3
问号只能出现在日期和星期这两个位置,表示这个位置的值不确定。这里简单写一下自己对*和?的理解,举个简单例子,如果我们指定每月2号执行操作,那么每月2号是星期几是不确定的,因此星期字段不能为* ,*表示所有的值,所以要用?,即我不关心2号是周几,它爱是周几是周几。
L("last") ("last") "L" 用在day-of-month字段意思是 "这个月最后一天";用在 day-of-week字段, 它简单意思是 "7" or "SAT"。 如果在day-of-week字段里和数字联合使用,它的意思就是 "这个月的最后一个星期几" – 例如: "6L" means "这个月的最后一个星期五". 当我们用“L”时,不指明一个列表值或者范围是很重要的,不然的话,我们会得到一些意想不到的结果。比如 0 15 10 ? * 6L 2002-2005
表示 2002年至2005年的每月的最后一个星期五上午10:15触发 , 0 0 23 L * ?
表示每月最后一天23点执行一次
二、 https://github.com/robfig/cron
package main //blog: xiaorui.cc import ( "github.com/robfig/cron" "log" ) func main() { i := 0 c := cron.New() spec := "0 */1 * * * *" c.AddFunc(spec, func() { i++ log.Println("start", i) }) c.Start() select{} //阻塞主线程不退出 }
AddFunc注册任务到调度器里,当任务要执行的时候会使用goroutines调用,这样每个任务都不会发生阻塞。其中注意select的用法: golang 的 select 的功能和 select, poll, epoll 相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。
更多参考 golang /robfig/cron库 的学习笔记
三、leaf的AfterFunc
Timer主要是提供一个Cron功能的定时器服务,其中Timer是time.AfterFunc的封装,是为了方便聚合到Skeleton中。
Go 语言标准库提供了定时器的支持:
func AfterFunc(d Duration, f func()) *Timer
AfterFunc 会等待 d 时长后调用 f 函数,这里的 f 函数将在另外一个 goroutine 中执行。Leaf 提供了一个相同的 AfterFunc 函数,相比之下,f 函数在 AfterFunc 的调用 goroutine 中执行,这样就避免了同步机制的使用:
skeleton.AfterFunc(5 * time.Second, func() { // ... })
这个功能也是通过一个通道来做的。
type Dispatcher struct { ChanTimer chan *Timer } func NewDispatcher(l int) *Dispatcher { disp := new(Dispatcher) disp.ChanTimer = make(chan *Timer, l) return disp } // Timer type Timer struct { t *time.Timer cb func() } func (disp *Dispatcher) AfterFunc(d time.Duration, cb func()) *Timer { t := new(Timer) t.cb = cb t.t = time.AfterFunc(d, func() { disp.ChanTimer <- t }) return t }
实质上构造了一个Timer类型,包含原生的time.Timer和到期执行的回调cb。然后原生Timer时间到了之后,把这个构造数据塞入通道disp.ChanTimer。在skeleton.Run里,会自动执行这些Cb
// leaf\module\skeleton.go func (s *Skeleton) Run(closeSig chan bool) { for { select { case <-closeSig: s.commandServer.Close() s.server.Close() for !s.g.Idle() || !s.client.Idle() { s.g.Close() s.client.Close() } return case ri := <-s.client.ChanAsynRet: s.client.Cb(ri) // 等待来自通道的数据 case ci := <-s.server.ChanCall: s.server.Exec(ci) case ci := <-s.commandServer.ChanCall: s.commandServer.Exec(ci) case cb := <-s.g.ChanCb: s.g.Cb(cb) case t := <-s.dispatcher.ChanTimer: t.Cb() } } }
在官方example_test.go中是手动执行 (<-d.ChanTimer).Cb()
.并且还演示了调用Stop方法将会清除一个定时器。
func ExampleTimer() { d := timer.NewDispatcher(10) // timer 1 d.AfterFunc(1, func() { fmt.Println("My name is Leaf") }) // timer 2 t := d.AfterFunc(1, func() { fmt.Println("will not print") }) t.Stop() // dispatch (<-d.ChanTimer).Cb() // Output: // My name is Leaf }
四、leaf的cron功能
看起来,是在github.com/robfig/cron库的基础上来做的。源码如下
// Cron type Cron struct { t *Timer } func (c *Cron) Stop() { if c.t != nil { c.t.Stop() } } func (disp *Dispatcher) CronFunc(cronExpr *CronExpr, _cb func()) *Cron { c := new(Cron) now := time.Now() nextTime := cronExpr.Next(now) if nextTime.IsZero() { return c } // callback var cb func() cb = func() { defer _cb() now := time.Now() nextTime := cronExpr.Next(now) if nextTime.IsZero() { return } c.t = disp.AfterFunc(nextTime.Sub(now), cb) } c.t = disp.AfterFunc(nextTime.Sub(now), cb) return c }
源码中使用了嵌套的倒计时调用cb。
func ExampleCron() { d := timer.NewDispatcher(10) // cron expr cronExpr, err := timer.NewCronExpr("0/3 * * * * *") if err != nil { fmt.Println("cron expr error:",err) return } // cron var c *timer.Cron c = d.CronFunc(cronExpr, func() { fmt.Println("My name is Leaf") //c.Stop() }) fmt.Println("begin cron",c) // dispatch (<-d.ChanTimer).Cb() select{ case t := <-d.ChanTimer: t.Cb() } // Output: // My name is Leaf }
虽然我把c.Stop给注释掉了,但也没有像我预想中一样,每隔3秒就打印一次 My name is Leaf
。
cronExpr, err := timer.NewCronExpr("0/3 * * * * *") now := time.Now() nextTime := cronExpr.Next(now) if nextTime.IsZero() { fmt.Println("nextTime is Zero") } fmt.Println("sub time",nextTime.Sub(now))
这个时间也不准呀:
sub time 1.8513635s
以上所述就是小编给大家介绍的《Golang 游戏leaf系列(六) time模块 cron表达式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Python正则表达式与re模块介绍
- 少说话多写代码之Python学习064——标准模块(正则表达式)
- 正则表达式 – 如何使用正则表达式进行Erlang模式匹配?
- lambda表达式
- 表达式 / 语句
- Python正则表达式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。