Go进阶:一文掌握Golang中Timer定时器的使用

定时器

项目经常会有需求:到达某一个特定的时刻就执行我们设定的逻辑,或者周期性的去执行某一个任务

Timer

Timer是一个一次性的时间定时器,在我们设定的某一个时刻将会执行一次

go 复制代码
// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
// unless the Timer was created by AfterFunc.
// A Timer must be created with NewTimer or AfterFunc.
type Timer struct {
   C <-chan Time
   r runtimeTimer
}
  • 其中的C是一个只读的Channel,如果在没有到达我们设定的时间的时候,管道内会没有数据写入,一直会处于阻塞的状态,到达设定的时间就会向管道写入一个系统时间,触发事件

创建Timer

scss 复制代码
// NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d.
func NewTimer(d Duration) *Timer

使用示例

go 复制代码
func main() {
   timer := time.NewTimer(2 * time.Second)
   <-timer.C
   fmt.Println("hello world")
}
  • 程序会在两秒之后打印"hello world",这两秒会一直阻塞,直到到达我们的超时时间

停止Timer

go 复制代码
func (t *Timer) Stop() boo
  • 返回值如果是true:还没有到达超时时间,在超时时间内就停止了timer
  • 返回值如果是false:执行stop()时,已经到达了超时时间
go 复制代码
func main() {
   timer := time.NewTimer(2 * time.Second)
   fmt.Println(timer.Stop())
}

重置Timer

go 复制代码
func (t *Timer) Reset(d Duration) bool
  • 对于已经过期或者已经失效的timer,可以通过重置方法使其继续生效

使用示例

go 复制代码
func main() {
   timer := time.NewTimer(2 * time.Second)
   <-timer.C
   fmt.Println("hello world 1")

   fmt.Println("stop 1 ", timer.Stop())

   timer.Reset(2 * time.Second)
   fmt.Println("stop 2 ", timer.Stop())
}

运行结果

arduino 复制代码
hello world 1
stop 1  false
stop 2  true 
  • <-timer.C阻塞,一直到超时时间,之后使用stop()就会出现false,timer.Reset重置之后Timer又生效,再使用stop()就会出现true

time.AfterFunc

go 复制代码
func AfterFunc(d Duration, f func()) *Timer 
  • 传入的参数为超时时间,还有一个具体的函数f,返回一个Timer的指针,作用是在创建出timer之后,在本Goroutine,等待设置的时间之后执行函数f
go 复制代码
func main() {
   timer := time.AfterFunc(time.Second*1, func() {
      fmt.Println("hello world")
   })
   defer timer.Stop()
   time.Sleep(2 * time.Second)
}

time.After

go 复制代码
func After(d Duration) <-chan Time {
   return NewTimer(d).C
}
  • 根据函数定义,传入时间参数,最后返回的就是新建Timer里面的管道,这个函数相当于实现了Timer
  • time.After 一般会配合select一起使用
go 复制代码
func main() {
   ch := make(chan struct{})
   go func() {

      time.Sleep(time.Second * 5)
      ch <- struct{}{}
   }()
   select {
   case <-ch:
      fmt.Println("channel data")
   case <-time.After(time.Second * 1):
      fmt.Println("time after")
   }
}
  • 使用select来监听两个Channel,第一个ch是五秒之后才会有数据,第二个是一秒之后就会有数据,所以会输出"time after"

Ticker

go 复制代码
func NewTicker(d Duration) *Ticker
  • NewTicker返回 一个Ticker对象

Ticker对象定义

go 复制代码
// A Ticker holds a channel that delivers ``ticks'' of a clock
// at intervals.
type Ticker struct {
   C <-chan Time // The channel on which the ticks are delivered.
   r runtimeTimer
}
  • Ticker和Timer对象一样,含有一个channel通道,每隔一段指定的时间会往里面发送数据,根据这个消息管道来触发事件,只有关闭Ticker对象才不会继续发送消息

使用示例

go 复制代码
func Watch() chan struct{} {
   ticker := time.NewTicker(2 * time.Second)
   ch := make(chan struct{})
   go func(ticker2 *time.Ticker) {
      defer ticker.Stop()
      for {
         select {
         case <-ticker.C:
            fmt.Println("ticker")
         case <-ch:
            fmt.Println("ch")
            return
         }
      }
   }(ticker)
   return ch
}
func main() {
   ch := Watch()
   time.Sleep(6 * time.Second)
   ch <- struct{}{}
   time.Sleep(2 * time.Second)
   close(ch)

}
  • 输出:

    ticker
    ticker
    ticker
    ch

注意:调用ticker.Stop只会停止ticker,但不会关闭ticker.C这个管道,所以我们还需一个一个channel来控制Goroutine的退出

相关推荐
0和1的舞者12 分钟前
基于Spring的论坛系统-前置知识
java·后端·spring·系统·开发·知识
invicinble1 小时前
对于springboot
java·spring boot·后端
码界奇点2 小时前
基于Spring Boot与Vue的校园后台管理系统设计与实现
vue.js·spring boot·后端·毕业设计·源代码管理
爱编程的小庄2 小时前
Rust 发行版本及工具介绍
开发语言·后端·rust
Apifox.3 小时前
测试用例越堆越多?用 Apifox 测试套件让自动化回归更易维护
运维·前端·后端·测试工具·单元测试·自动化·测试用例
sunnyday04264 小时前
Nginx与Spring Cloud Gateway QPS统计全攻略
java·spring boot·后端·nginx
康王有点困4 小时前
Link入门
后端·flink
海南java第二人4 小时前
Spring Boot全局异常处理终极指南:打造优雅的API错误响应体系
java·spring boot·后端
小楼v4 小时前
消息队列的核心概念与应用(RabbitMQ快速入门)
java·后端·消息队列·rabbitmq·死信队列·交换机·安装步骤
小北方城市网5 小时前
接口性能优化实战:从秒级到毫秒级
java·spring boot·redis·后端·python·性能优化