golang提供了两种定时器。
一次性定时器–Timer,定时器只计时一次,计时结束遍停止运行
周期性定时器–Ticker,定时器周期的进行计时,除非注定停止,否则永远运行
一、Timer
Timer是一种单一事件的定时器,经过指定的时间后出发一个事件,这个事件通过其本身提供的channel进行通知。
一、结构
1 | type Timer struct { |
- C 管道类型的变量,上层调用者通过此管道接收事件。
- r runtime定时器,该定时器即系统管理的定时器,上层不可见。
当定时器过期,当前时间会被发送到C上。除非定时器是通过AfterFunc创建。
二、代码结构
1 |
|
- NewTimer、AfterFunc 是两个创建方法,NewTimer过期后会执行send方法把当前时间发送到C,AfterFunc方法会在过期后执行传入的方法。
- Stop 停止当前Timer。
- Reset 重置当前Timer。
- After 会返回当前Timer的通道。
三、底层实现
Timer和Ticker有个重要的runtimeTimer类型的变量。
1 | type runtimeTimer struct { |
- tb 系统底层存储runtimeTimer的数组地址
- i 当前runtimeTimer在tb数组中的下标
- when 定时器出发的时间
- period 定时器周期性触发间隔(Timer的值为0)
- f 定时器出发时执行的回调函数,回调函数接收两个参数
- arg 定时器触发时执行回调函数的参数之一
- seq 定时器触发时间执行回调函数的参数二(Timer不使用该参数)
1、NewTimer
1 | func NewTimer(d Duration) *Timer { |
方法中初始化一些必要的变量信息,然后通过startTimer()交给系统协程维护。
when()是计算下一次定时器触发的绝对时间。
sendTime()是定时器触发时的动作。
2、Stop
1 | func (t *Timer) Stop() bool { |
此处致使简单的把Timer从系统协程中移除。但是并不会关闭通道。
如果Timer已经触发,Stop返回false。如果Timer还未触发,则Stop返回true。
3、Reset
1 | func (t *Timer) Reset(d Duration) bool { |
重置方法相对简单,先停止当前的定时器。然后创建新的定时器。其返回值与Stop类似。
4、After
1 | func After(d Duration) <-chan Time { |
After方法也是非常简单,返回当前定时器的通道够上层应用。
4、AfterFunc
1 | func AfterFunc(d Duration, f func()) *Timer { |
AfterFunc方法和NewTimer方法类似,只是把sendTime变成了一个用户自定义的方法。