Golang的Timer类,是一个普遍意义上的定时器,它有着普通定时器的一些特性,例如:
给定一个到期时间,和一个回调函数,到期后会调用回调函数
重置定时器的超时时间
停止定时器
Golang的Timer在源码中,实现的方式是以一个小顶堆来维护所有的Timer集合。
package main
import (
"fmt"
"time"
)
func main() {
aChan := make(chan int, 1)
ticker := time.NewTicker(time.Second * 1)
go func() {
for {
select {
case <-ticker.C:
fmt.Printf("ticked at %v\n", time.Now())
}
}
}()
//阻塞主线程
<-aChan
}
定时器是开发的基本组件
以下这些摘自博客
https://www.ibm.com/developerworks/cn/linux/l-cn-timers/
定时器的基本模型
StartTimer(Interval, TimerId, ExpiryAction)
注册一个时间间隔为 Interval 后执行 ExpiryAction 的定时器实例,其中,返回 TimerId 以区分在定时器系统中的其他定时器实例。
StopTimer(TimerId)
根据 TimerId 找到注册的定时器实例并执行 Stop 。
PerTickBookkeeping()
在一个 Tick 内,定时器系统需要执行的动作,它最主要的行为,就是检查定时器系统中,是否有定时器实例已经到期。注意,这里的 Tick 实际上已经隐含了一个时间粒度 (granularity) 的概念。
ExpiryProcessing()
在定时器实例到期之后,执行预先注册好的 ExpiryAction 行为。
定时器分类
上面说了基本的定时器模型,但是针对实际的使用情况,又有以下 2 种基本行为的定时器:
Single-Shot Timer
这种定时器,从注册到终止,仅仅只执行一次。
Repeating Timer
这种定时器,在每次终止之后,会自动重新开始。
本质上,可以认为 Repeating Timer 是在 Single-Shot Timer 终止之后, 再次注册到定时器系统里的 Single-Shot Timer,因此,
在支持 Single-Shot Timer 的基础上支持
Repeating Timer 并不算特别的复杂。
实现方式
1 基于链表和信号实现定时器
2 基于 2.6 版本内核定时器的实现 (Posix 实时定时器 )
3 最小堆实现的定时器
4 基于时间轮 (Timing-Wheel) 方式实现的定时器
这个很有意思
实现方式 StartTimer StopTimer PerTickBookkeeping
基于链表 O(1) O(n) O(n)
基于排序链表 O(n) O(1) O(1)
基于最小堆 O(lgn) O(1) O(1)
基于时间轮 O(1) O(1) O(1)