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的退出

相关推荐
一只叫煤球的猫5 分钟前
开个新坑,从头开始完整拆解 Spring AI 2.0 的源码
后端·面试·aigc
自进化Agent智能体36 分钟前
Hermes Cron 定时任务 —— 让 Agent 自动工作
后端
我不是码神661 小时前
Windows 下 Codex CLI 报“拒绝访问 (os error 5)”:先查入口,再查配置
后端·chatgpt
她的男孩1 小时前
我用 LLM 把后台 CRUD 效率提升 10 倍:AI 代码生成器的架构与落地实践
java·后端·架构
程序员cxuan1 小时前
本地跑一个 Qwen 3.8,你将拥有一个 Opus 4.6
人工智能·后端·程序员
凤山老林2 小时前
高保真集成测试:Spring Boot 结合 Testcontainers 的工程落地
spring boot·后端·集成测试
步行cgn2 小时前
MyBatis <trim> 标签完全解析:动态 SQL 的终极武器
后端
XPoet2 小时前
AI 编程工程化:实战——从 0 到 1 搭建 AI 编程工作流
前端·后端·ai编程
掘金者阿豪2 小时前
向量数据库不是终点,企业AI真正需要的是融合数据库
后端
程序员cxuan2 小时前
OpenAI Linux 版来了!
人工智能·后端·程序员