首先time.Timer和 time.NewTicker属于定时器,二者的区别在于
timer : 到固定时间后会执行一次,请注意是一次,而不是多次。但是可以通过reset来实现每隔固定时间段执行
ticker : 每隔固定时间都会触发,多次执行. 具体请查看下面示例1
time.After : 用于实时超时控制,常见主要和select channel结合使用.查看代码示例2
//示例1
package main
import (
"fmt"
"sync"
"time"
)
// timer 和 ticker 区别
// timer 是到固定时间后会执行一次
// ticker 每隔固定时间都会触发 常用的一种定时器
func main() {
var wg sync.WaitGroup
wg.Add(2)
timer := time.NewTimer(time.Second * 3)
go func(t *time.Timer) {
defer wg.Done()
for {
<-t.C
fmt.Println("timer", time.Now().Format("2006-01-02 15:04:05"))
//利用Reset可以实现timer每隔固定时间段触发。reset 重新开始计时,如果调用时 t 还在等待中会返回真;如果 t已经到期或者被停止了会返回假。可自行打印查看结果
// t.Reset(2 * time.Second)
//expire := t.Reset(2 * time.Second)
//fmt.Println("expire:",expire)
}
}(timer)
ticker := time.NewTicker(time.Second * 4)
go func(t *time.Ticker) {
defer wg.Done()
for {
<-t.C
fmt.Println("ticker", time.Now().Format("2006-01-02 15:04:05"))
}
}(ticker)
wg.Wait()
}
//timer未使用reset的执行结果如下:
/*
timer 2021-01-05 15:06:34
ticker 2021-01-05 15:06:35
ticker 2021-01-05 15:06:39
ticker 2021-01-05 15:06:43
....
....
....
*/
// timer使用reset的执行结果如下:
/*
timer 2021-01-05 15:19:08
ticker 2021-01-05 15:19:09
timer 2021-01-05 15:19:10
timer 2021-01-05 15:19:12
ticker 2021-01-05 15:19:13
timer 2021-01-05 15:19:14
timer 2021-01-05 15:19:16
...
...
...
*/
// 示例2
package main
import (
"time"
"fmt"
)
func main() {
ch := make(chan string)
go func() {
time.Sleep(time.Second * 2)
ch <- "result"
}()
select {
case res := <-ch:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("timeout")
}
}
再知道二者的区别之后,是否发现了上面有缺陷。没有关闭定时器的执行。定时器未关闭!!!!大家会想到stop ,使用stop注意是在协程内还是携程外,以及使用的场景业务
协程退出时需要关闭,避免资源l浪费,使用defer ticker.Stop()
package main
import (
"fmt"
"time"
)
//定时器的stop
func main() {
// 协程内的定时器 stop 在协程结束时,关闭默认资源定时器,channel 具体根据业务来看
go func() {
ticker := time.NewTicker(5 * time.Second)
// 此处 可以简化为defer ticker.Stop()
defer func() {
fmt.Println("stop")
ticker.Stop()
}()
select {
case <- ticker.C:
fmt.Println("ticker..." )
}
}()
// 停止ticker
stopChan := make(chan bool)
ticker := time.NewTicker(5 * time.Second)
go func(ticker *time.Ticker) {
defer func() {
ticker.Stop()
fmt.Println("Ticker2 stop")
}()
for {
select {
case s := <-ticker.C:
fmt.Println("Ticker2....",s)
case stop := <-stopChan:
if stop {
fmt.Println("Stop")
return
}
}
}
}(ticker)
// 此处的stop 并不会结束上面协程,也不会打印出 Ticker2 stop 只能借助stopChan,让协程结束时关闭ticker或者协程出现panic时执行defer
//ticker.Stop()
stopChan <- true
close(stopChan)
time.Sleep(time.Second * 10)
fmt.Println("main end")
}
实际使用场景的代码示例
package main
import (
"fmt"
"time"
)
// 每秒钟调⽤⼀次 proc 并保证程序不退 出
func main() {
go func() {
t := time.NewTicker(time.Second * 1)
defer func() {
t.Stop()
}()
// 1 在这⾥需要你写算法
// 2 要求每秒钟调⽤⼀次proc函数
// 3 要求程序不能退出
for {
select {
case <-t.C:
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
proc()
}()
}
}
// timer执行
//for {
// // 1.当前时间
// now := time.Now()
// // 1.间隔1秒时长
// next := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()+1, 0, now.Location())
// t := time.NewTimer(next.Sub(now))
// //
// go func() {
// defer func() {
// if err := recover(); err != nil {
// fmt.Println(err)
// }
// }()
// proc()
// }()
// <- t.C
//}
}()
select {
}
}
func proc() {
panic("ok")
}