Go语言中定时器的使用
程序员文章站
2022-07-06 12:51:03
GO语言在time包中提供了三种定时器的使用方式: 1.第一种:ticker // A Ticker holds a channel that delivers `ticks' of a clock // at intervals. type Ticker struct { C <-chan Tim ......
go语言在time包中提供了三种定时器的使用方式:
1.第一种:ticker
// a ticker holds a channel that delivers `ticks' of a clock
// at intervals.
type ticker struct {
c <-chan time // the channel on which the ticks are delivered.
r runtimetimer
}
通过 time.newticker() 创建,这种类型,ticker会不断的按照设定的间隔时间触发,除非主动终止运行。
2.第二种:timer
// the timer type represents a single event.
// when the timer expires, the current time will be sent on c,
// unless the timer was created by afterfunc.
// a timer must be created with newtimer or afterfunc.
type timer struct {
c <-chan time
r runtimetimer
}
通过 time.newtimer() 创建,这种类型,timer只会执行一次,当然,可以在执行完以后通过调用 timer.reset() 让定时器再次工作,并可以更改时间间隔。
3.第三种:after()
// after waits for the duration to elapse and then sends the current time
// on the returned channel.
// it is equivalent to newtimer(d).c.
// the underlying timer is not recovered by the garbage collector
// until the timer fires. if efficiency is a concern, use newtimer
// instead and call timer.stop if the timer is no longer needed.
func after(d duration) <-chan time {
return newtimer(d).c
}
从代码可以看到,after()其实是timer的一个语法糖。
下面通过代码演示一下三种方式的使用:
1.ticker
1 ticker := time.newticker(time.second * 1) // 运行时长 2 ch := make(chan int) 3 go func() { 4 var x int 5 for x < 10 { 6 select { 7 case <-ticker.c: 8 x++ 9 fmt.printf("%d\n", x) 10 } 11 } 12 ticker.stop() 13 ch <- 0 14 }() 15 <-ch // 通过通道阻塞,让任务可以执行完指定的次数。
该ticker每1秒触发一次,即ticker.c中每一秒会有一个内容加入,最后通过向ch中写入数字,让程序解除阻塞,继续执行。
2.timer
1 timer := time.newtimer(time.second * 1) // timer 只能按时触发一次,可通过reset()重置后继续触发。 2 go func() { 3 var x int 4 for { 5 select { 6 case <-timer.c: 7 x++ 8 fmt.printf("%d,%s\n", x, time.now().format("2006-01-02 15:04:05")) 9 if x < 10 { 10 timer.reset(time.second * 2) 11 } else { 12 ch <- x 13 } 14 } 15 } 16 }() 17 <-ch
3.after()
1 // 阻塞一下,等待主进程结束 2 tt := time.newtimer(time.second * 10) 3 <-tt.c 4 fmt.println("over.") 5 6 <-time.after(time.second * 4) 7 fmt.println("再等待4秒退出。tt 没有终止,打印出 over 后会看见在继续执行...") 8 tt.stop() 9 <-time.after(time.second * 2) 10 fmt.println("tt.stop()后, tt 仍继续执行,只是关闭了 tt.c 通道。")
4.我们可以利用这些基本的方法,设计自己的定时任务管理。
1 type jobfunc2 func(j *job) 2 3 type job struct { 4 jf jobfunc2 5 params map[string]interface{} 6 ch chan int 7 } 8 9 func newjob() *job { 10 return &job{ 11 params: make(map[string]interface{}), 12 ch: make(chan int), 13 } 14 } 15 16 func (j *job) run(t time.duration) { 17 ticker := time.newticker(time.second * t) 18 go func() { 19 for { 20 select { 21 case <-ticker.c: 22 j.jf(j) 23 case <-j.ch: 24 fmt.println("收到结束指令") 25 ticker.stop() 26 break 27 } 28 } 29 }() 30 31 } 32 33 func main() { 34 j := newjob() 35 j.jf = func(jj *job) { 36 fmt.println("定时任务执行...", time.now().format("15:04:05 2006-02-01"), jj.params) 37 } 38 j.params["p1"] = "第一个参数" 39 j.params["p2"] = 100 40 j.run(1) 41 42 // 阻塞一下,等待主进程结束 43 tt := time.newtimer(time.second * 10) 44 <-tt.c 45 fmt.println("over.") 46 47 <-time.after(time.second * 4) 48 fmt.println("再等待4秒退出。tt 没有终止,打印出 over 后会看见在继续执行...") 49 tt.stop() 50 <-time.after(time.second * 2) 51 fmt.println("tt.stop()后, tt 仍继续执行,只是关闭了 tt.c 通道。") 52 }
部分执行结果截图:
最后补充一下,通过channel去终止任务的执行。
1 // 阻塞一下,等待主进程结束 2 tt := time.newtimer(time.second * 10) 3 <-tt.c 4 fmt.println("over.") 5 6 <-time.after(time.second * 4) 7 fmt.println("再等待4秒退出。tt 没有终止,打印出 over 后会看见在继续执行...") 8 tt.stop() 9 <-time.after(time.second * 2) 10 fmt.println("tt.stop()后, tt 仍继续执行,只是关闭了 tt.c 通道。") 11 j.ch <- 0 12 <-time.after(time.second * 2) 13 fmt.println("又等了2秒钟...这两秒钟可以看到 tt 没干活了...")
在go语言编写中,要熟练使用 channel。