很多时候我们需要用到定时器,比如定期执行一段逻辑。Go语言中用到最多无外乎几种:
- time.Sleep()
- time.NewTimer()
- time.After()
- time.NewTicker()
这三种底层逻辑都是相通的。具体看网上的介绍。
Sleep和NewTimer
这两个方法类似,你可能会发现NewTimer的实现是放在sleep.go文件当中的。这两种方法都是等待指定的时间长度,只不过sleep直接阻塞执行流,NewTimer是通过发送通道信号的方式,一般用在不同协程间。他们都是一次性的,不会像NewTicker一样定时循环。
NewTimer可以通过Reset()方法再次指定时间激活。
time.After是基于NewTimer实现的,这里不介绍。
NewTicker重点分析
先看一下最常见的用法
2023/02/16 16:26:15 Ticker counter: 1
2023/02/16 16:26:17 Ticker counter: 2
2023/02/16 16:26:19 Ticker counter: 3
2023/02/16 16:26:21 Ticker counter: 4
2023/02/16 16:26:23 Ticker counter: 5
2023/02/16 16:26:25 Ticker counter: 6
2023/02/16 16:26:27 Ticker counter: 7
2023/02/16 16:26:29 Ticker counter: 8
2023/02/16 16:26:31 Ticker counter: 9
2023/02/16 16:26:33 Ticker counter: 10
2023/02/16 16:26:35 Ticker counter: 11
2023/02/16 16:26:37 Ticker counter: 12
2023/02/16 16:26:38 Ticker ready to exit.
2023/02/16 16:26:39 Ticker counter: 13
2023/02/16 16:26:41 Ticker counter: 14
2023/02/16 16:26:43 Ticker counter: 15
2023/02/16 16:26:43 Ticker demo exit.
2023/02/16 16:26:48 Bye.
time.Sleep(10 * time.Second)
2023/02/16 16:02:51 Ticker counter: 1
2023/02/16 16:03:01 Ticker counter: 2
2023/02/16 16:03:11 Ticker counter: 3
2023/02/16 16:03:14 Ticker ready to exit.
2023/02/16 16:03:21 Ticker demo exit.
2023/02/16 16:03:24 Bye.
time.Sleep(9 * time.Second)
2023/02/16 16:30:05 Ticker counter: 1
2023/02/16 16:30:14 Ticker counter: 2
2023/02/16 16:30:23 Ticker counter: 3
2023/02/16 16:30:28 Ticker ready to exit.
2023/02/16 16:30:32 Ticker counter: 4
2023/02/16 16:30:38 Bye.
各种修改参数测试之后,这里得出几个结论:
- NewTicker第一次触发是在经过第一个时间间隔之后,而不是创建时。
- 如果ticker.C没被接收,下次时间间隔到了产生的新信号直接丢弃,而不会累计。
- 通道select语法其中一个case阻塞的话,其它case即使有通道数据到达也无法运行。
标准库源码分析
参考阅读:
标准库的定时器精度能做到MS级别,但是大量的定时任务对运行时性能影响会比较大,因为精度太高。
时间轮定时器
参考阅读:
时间轮方案被设计来处理大量定时任务,该方案能尽量减少循环遍历带来的性能下降。
(完)