Golang-定时器和断续器
个人博客网站:** https://www.sakurasss.top ( 最近打算把个人博客里的那些文章也慢慢移过来吧 )
1. 基本介绍
Timer&Ticker是 Go 标准包 time 中定义的类型,通过 Channel 与程序进行通信
// 定时器
time.Timer
// 断续器
time.Ticker
定时器 Timer 类似于一次性闹钟
断续器 Ticker 类似于重复性闹钟,也称为循环定时器
应用场景 : 定时任务 , 程序每隔多长时间执行一次 , 程序某个时间点开始结束
2. 定时器
使用语法
// time.NewTimer
func NewTimer(d Duration) *Timer
创建定时器 , 参数是 Duration 时间。返回为 *Timer。*Timer.C是用来接收到期通知的单向 Channel
type Timer struct {
C <-chan Time
}
只要能从*Timer.c上接收数据 , 就意味着定时器到时了 , 接收到的元素是time.Time 类型的数据 , 为到时时间
2.1 定时器典型使用
func TimerAA() {
// 创建定时器
t := time.NewTimer(2 * time.Second)
fmt.Println("定时器开始计时:", time.Now().String())
end := <-t.C
fmt.Println("定时器定时结束:", end.String())
}
2.2 定时器停止和重置
// 停止计时器
// 返回值bool类型,返回false,表示该定时器早已经停止,返回true表示由本次调用停止
func (t *Timer) Stop() bool
// 重置定时器
// 返回值bool类型,返回false,表示该定时器早已经停止,返回true表示由本次调用重置
func (t *Timer) Reset(d Duration) bool
注意:
停止和重置是定时器没有结束的时候才能调用的
一旦能从time.C 中拿到内容说明定时器以及结束了 , 此时调用Stop 和Reset没有意义
- 猜数组游戏 , 一共猜五次 , 每次 3 秒
func TimerStop() {
// 初始化数组
ch := make(chan int)
// 每隔0.4秒猜一次
go func() {
for {
ch <- rand.Intn(10)
time.Sleep(400 * time.Millisecond)
}
}()
// 每一局时间
t := time.NewTimer(3 * time.Second)
// 统计猜中次数和未猜中次数
GuessYes, GuessNo := 0, 0
// 五轮猜数字游戏
for i := 0; i < 5; i++ {
Guess:
for {
select {
case value := <-ch:
fmt.Println("猜的数字为: ", value)
if value == 5 {
fmt.Println("猜中了数字")
GuessYes++
// 重置定时器,开始下一轮游戏
t.Reset(time.Second * 3)
break Guess
}
case <-t.C:
fmt.Println("时间结束,没有猜中数字")
GuessNo++
// 重新创建定时器
t = time.NewTimer(3 * time.Second)
break Guess
}
}
}
fmt.Println("游戏结束,猜中次数为: ", GuessYes, "失败次数为", GuessNo)
}
2.3 不需要定时器的关闭和重置
func After(d Duration) <-chan Time
返回值是定时器到期的通知 Channel , 不需要从 t.c 中取数据
func TimerChannel() {
ch := time.After(5 * time.Second)
fmt.Println("设置定时器: ", time.Now().String())
now := <-ch
fmt.Println("定时器结束: ", now.String())
}
2.4 定时器结束执行特定函数
func AfterFunc(d Duration, f func()) *Timer
3. 断续器 ( 循环定时器 )
func NewTicker(d Duration) *Ticker
创建断续器。参数是 Duration 时间。返回为 *Ticker。*Ticker.C是用来接收到期通知的单向 Channel
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
}
因此我们只要可从 *Ticker.C上接收数据,就意味着断续器时间到。接收到的元素是 time.Time 类型数据,为到时时间。当接收到到期时间后,间隔下一个Duration还会再次接收到到期时间。
// Ticket 方法
// 停止断续器
func (t *Ticker) Stop()
// 重置断续器间隔时间
func (t *Ticker) Reset(d Duration)
- 模拟定期心跳检测的案例
func TickerHeart() {
// 断续器,每隔两秒做一次心跳检测
ticker := time.NewTicker(2 * time.Second)
// 定时器,表示只执行五次10秒的心跳检测
// 不用定时器就是一直执行每隔两秒的心跳检测
timer := time.NewTimer(10 * time.Second)
loop:
for now := range ticker.C {
// 心跳检测
fmt.Println("心跳检测 , http://domain/ping , ", now.String())
// 非阻塞读ticker
select {
case <-timer.C:
ticker.Stop()
fmt.Println("心跳检测结束")
break loop
default:
// 无阻塞的接收操作
}
}
}