Ticker是周期性定时器.即周期性的触发一个事件.通过Ticker本身提供的管道将事件
传递出去.
Ticker数据结构:
源码位置:src/time/tick.go
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
initTicker bool
}
Ticker对外仅暴露了一个channel.当指定时间到来时就往该channel中写入系统时
间.即一个事件.
1.简单定时任务:
func main() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for range ticker.C {
log.Println("tick")
}
}
执行结果:
定时聚合任务:
示例:
func TickerLaunch() {
//5分钟执行一次.
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
maxPassenger := 30
passengers := make([]string, 0, maxPassenger)
for {
passenger := GetNewPassenger()
if passenger != "" {
passengers = append(passengers, passenger)
} else {
time.Sleep(1 * time.Second)
}
select {
case <-ticker.C:
Launch(passengers)
passengers = []string{}
default:
if len(passengers) >= maxPassenger {
Launch(passengers)
passengers = []string{}
}
}
}
}
func Launch(passengers []string) {
for i := range passengers {
fmt.Println(passengers[i], "发车了")
}
}
func GetNewPassenger() string {
return "乘客"
}
2.Ticker对外接口:
1)创建定时器:
源码位置:src/time/tick.go
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic("non-positive interval for NewTicker")
}
// Give the channel a 1-element time buffer.
// If the client falls behind while reading, we drop ticks
// on the floor until the client catches up.
c := make(chan Time, 1)
t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c))))
t.C = c
return t
}
2).停止定时器:
源码位置:src/time/tick.go
// Stop turns off a ticker. After Stop, no more ticks will be sent.
// Stop does not close the channel, to prevent a concurrent goroutine
// reading from the channel from seeing an erroneous "tick".
func (t *Ticker) Stop() {
if !t.initTicker {
// This is misuse, and the same for time.Timer would panic,
// but this didn't always panic, and we keep it not panicking
// to avoid breaking old programs. See issue 21874.
return
}
stopTimer((*Timer)(unsafe.Pointer(t)))
}
流程图:
总流程图:
3.简单接口:
在有些场景下.启动一个定时器后.该定时器永远不会停止.比如定时轮询任务.此时可
以使用一个简单的Tick函数来获取定时器的管道.函数如下:
源码位置:src/runtime/tick.go
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
}
从源码可以看出其实是创建了一个Ticker.然后只返回了管道.并没有返回ticker.所以
没有办法停止.
4.错误示例:
当Ticker用于for循环时.很容易出现意想不到的资源泄漏问题.
示例:
func WrongTicker() {
for {
select {
case <-time.Tick(time.Second):
log.Printf("resource leak!")
}
}
}
上面的代码.select每次检测case语句都会创建一个定时器.for循环又会不断的执行
select语句.系统里会有越来越多的定时器不断地消耗CPU资源.最终CPU资源被耗
尽.
如果大家喜欢我的分享的话.可以关注我的微信公众号
念何架构之路