1、前言
在进行并发编程时,有时候会需要定时功能,比如监控某个GO程是否会运行过长时间、定时打印日志等等。
GO标准库中的定时器主要有两种,一种为Timer定时器
,一种为Ticker定时器
。
Timer计时器使用一次后,就失效了,需要Reset()
才能再次生效。而Ticker计时器会一直生效,接下来分别对两种进行介绍。
2、Timer定时器
时间到了,执行只执行1次
GO定时器的实现原理:
在一个GO进程中,其中的所有计时器都是由一个运行着 timerproc() 函数的 goroutine 来保护。
它使用时间堆(最小堆)的算法来保护所有的 Timer,其底层的数据结构基于数组的最小堆,堆顶的元素是间隔超时最近的 Timer,这个 goroutine 会定期 wake up,读取堆顶的 Timer,执行对应的 f 函数或者 sendtime()函数(下文会对这两个函数进行介绍),而后将其从堆顶移除。
Timer的结构:
type Timer struct {
C <-chan Time
r runtimeTimer
}
Timer中对外暴露的只有一个channel,这个 channel 也是定时器的核心。当计时结束时,Timer会发送值到channel中,外部环境在这个 channel 收到值的时候,就代表计时器超时了,可与select搭配执行一些超时逻辑。
可以通过 time.NewTimer
、time.AfterFunc
或者 time.After
对一个 Timer进行创建。
示例代码:
func main(){
// 1.timer基本使用
//timer1 := time.NewTimer(2 * time.Second)
//t1 := time.Now()
//fmt.Printf("t1:%v\n", t1)
// 无缓冲通道,在没有获取到值时,会阻塞程序
//t2 := <-timer1.C
//fmt.Printf("t2:%v\n", t2)
// 2.验证timer只能响应1次
//timer2 := time.NewTimer(time.Second)
//for {
// xt2 := <-timer2.C
// fmt.Printf("xt2:%v\n", xt2)
// fmt.Println("时间到")
//}
// 想要再次使用必须使用 Reset 方法重置
//timer2 := time.NewTimer(time.Second)
//xt2_1 := <-timer2.C
//fmt.Printf("xt2_1:%v\n", xt2_1)
//fmt.Println("时间到")
//
//timer2.Reset(time.Second)
//xt2_2 := <-timer2.C
//fmt.Printf("xt2_2:%v\n", xt2_2)
//fmt.Println("时间到")
// 3.timer实现延时的功能
// (1)
//fmt.Printf("Sleep before:%v\n", time.Now())
//time.Sleep(time.Second)
//fmt.Printf("Sleep after:%v\n", time.Now())
// (2)
//timer3 := time.NewTimer(2 * time.Second)
//xt3 := <-timer3.C
//fmt.Printf("xt3:%v\n", xt3)
//fmt.Println("xt3 ---- 2秒到")
// (3)
//xt4 := <-time.After(2*time.Second)
//fmt.Printf("xt4:%v\n", xt4)
//fmt.Println("xt4 ---- 2秒到")
// 4.停止定时器
//timer4 := time.NewTimer(2 * time.Second)
//go func() {
// <-timer4.C
// fmt.Println("定时器执行了")
//}()
//b := timer4.Stop()
//if b {
// fmt.Println("timer4已经关闭")
//}
// 5.重置定时器
timer5 := time.NewTimer(3 * time.Second)
timer5.Reset(1 * time.Second)
fmt.Println(time.Now())
fmt.Println(<-timer5.C)
// 阻塞程序
for {
}
}
3、Ticker定时器
时间到了,多次执行
Ticker定时器可以周期性地不断地触发时间事件,不需要额外的Reset操作。
其使用方法与Timer大同小异,也包含 Stop
、Reset
等方法。
直接创建的方式有:time.NewTicker
、time.Tick
func main(){
ticker1 :=time.NewTicker(time.Second)
go func() {
for{
select {
case t1 := <-ticker1.C:
fmt.Println("t1 = ", t1)
}
}
}()
for{
}
}
作者:joker.liu 创建时间:2023-04-19 15:44
最后编辑:joker.liu 更新时间:2023-04-21 14:33
最后编辑:joker.liu 更新时间:2023-04-21 14:33