💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## Timer原理 Timer实际上是一种单一事件的定时器,即经过指定的时间后触发一个事件,这个事件通过其本身提供的channel进行通知。之所以叫单一事件,是因为Timer只执行一次就结束,这也是Timer与Ticker的最重要的区别之一。 通过timer.NewTimer(d Duration)可以创建一个timer,参数即等待的时间,时间到来后立即触发一个事件。 源码包`src/time/sleep.go:Timer`定义了Timer数据结构: ~~~go type Timer struct { // Timer代表一次定时,时间到来后仅发生一个事件。 C <-chan Time r runtimeTimer } ~~~ Timer对外仅暴露一个channel,指定的时间到来时就往该channel中写入系统时间,也即一个事件 ## Timer使用场景 ### 设定超时时间 有时我们希望从一个管道中读取数据,在管道中没有数据时,我们不想让程序永远阻塞在管道中,而是设定一个超时时间,在此时间段中如果管道中还是没有数据到来,则判定为超时。 Go源码包中有大量类似的用法,比如从一个连接中等待数据,其简单的用法如下代码所示: ~~~go func WaitChannel(conn <-chan string) bool { timer := time.NewTimer(1 * time.Second) select { case <- conn: timer.Stop() return true case <- timer.C: // 超时 println("WaitChannel timeout!") return false } } ~~~ WaitChannel作用就是检测指定的管道中是否有数据到来,通过select语句轮询conn和timer.C两个管道,timer会在1s后向timer.C写入数据,如果1s内conn还没有数据,则会判断为超时。 ### 延迟执行某个方法 有时我们希望某个方法在今后的某个时刻执行,如下代码所示: ~~~go func DelayFunction() { timer := time.NewTimer(5 * time.Second) select { case <- timer.C: log.Println("Delayed 5s, start to do something.") } } ~~~ DelayFunction()会一直等待timer的事件到来才会执行后面的方法(打印) 延迟执行另外一个方法:AfterFunc() ~~~go func AfterFunc(d Duration, f func()) *Timer ~~~ 该方法在指定时间到来后会执行函数f。例如: ~~~go func AfterFuncDemo() { log.Println("AfterFuncDemo start: ", time.Now()) time.AfterFunc(1 * time.Second, func() { log.Println("AfterFuncDemo end: ", time.Now()) }) time.Sleep(2 * time.Second) // 等待协程退出 } ~~~ AfterFuncDemo()中先打印一个时间,然后使用AfterFunc启动一个定器,并指定定时器结束时执行一个方法打印结束时间。 注意:time.AfterFunc()是异步执行的,所以需要在函数最后sleep等待指定的协程退出,否则可能函数结束时协程还未执行 ### 匿名定时器 `func After(d Duration) <-chan Time`方法创建一个定时器,并返回定时器的管道,如下代码所示: ~~~go func AfterDemo() { log.Println(time.Now()) <- time.After(1 * time.Second) log.Println(time.Now()) } ~~~ AfterDemo()两条打印时间间隔为1s,实际还是一个定时器,但代码变得更简洁 ### Timer使用案例 时间只执行1次 ~~~ 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 { // <-timer2.C // fmt.Println("时间到") //} // 3.timer实现延时的功能 //(1) //time.Sleep(time.Second) //(2) //timer3 := time.NewTimer(2 * time.Second) //<-timer3.C //fmt.Println("2秒到") //(3) //<-time.After(2*time.Second) //fmt.Println("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 { } } ~~~ 多次执行 ~~~ func main() { // 1.获取ticker对象 ticker := time.NewTicker(1 * time.Second) i := 0 // 子协程 go func() { for { //<-ticker.C i++ fmt.Println(<-ticker.C) if i == 5 { //停止 ticker.Stop() } } }() for { } } ~~~