当前位置: 首页 > ai >正文

Go语言 定时器

        我们常常会有这样的场景:比如到了未来某一时刻,需要某个逻辑或者某个任务执行一次,或者是周期性的的执行多次,有点类似定时任务。这种场景就需要用到定时器,Go语言中也内置了定时器的实现,timerticker

Timer

   Timer是一种一次性时间定时器,即在未来某个时刻,触发的事件只会执行一次

Timer的结构定义

type Timer struct {C <-chan Timer runtimeTimer
}

  Timer结构里有一个Time类型的管道C,主要用于事件通知。在未到达设定时间的时候,管道内没有数据写入,一直处于阻塞状态,到达设定时间后,会向管道内写入一个系统时间,触发事件。 

创建Timer

func NewTimer(d Duration) *Timer

使用示例:

package mainimport ("fmt""time"
)func main() {timer := time.NewTimer(2 * time.Second) //设置超时时间2s<-timer.Cfmt.Println("after 2s Time out!")
}

运行结果:

after 2s Time out!

        程序在2s后打印"after 2s Time out!",因为创建了一个定时器timer,设置了超时时间为2s,执行<-timer.C会一直阻塞,直到2s后,程序继续执行。 

停止Timer

func (t *Timer) Stop() bool

返回值:

  • true执行stop()timer还没有到达超时时间,即超时时间内停止了timer
  • false执行stop()timer到达了超时时间,过了超时时间才停止timer

使用示例:

package mainimport ("fmt""time"
)func main()  {timer := time.NewTimer(2 * time.Second) //设置超时时间2sres := timer.Stop()fmt.Println(res)
}

运行结果:

true

重置Timer

func (t *Timer) Reset(d Duration) bool

对于已经过期或者是已经停止的timer,可以通过重置方法激活使其继续生效。
使用示例: 

package mainimport ("fmt""time"
)func main() {timer := time.NewTimer(time.Second * 2)<-timer.Cfmt.Println("time out1")res1 := timer.Stop()fmt.Printf("res1 is %t\n", res1)timer.Reset(time.Second * 3)res2 := timer.Stop()fmt.Printf("res2 is %t\n", res2)
}

运行结果:

time out1
res1 is false
res2 is true

        程序2s之后打印"time out1",此时timer已经过期了,所以res1的值为false,接下来执行timer.Reset(time.Second * 3)又使timer生效了,并且重设超时时间为3s,但是紧接着执行了timer.Stop(),还未到超时时间,所以res2的值为true。 

time.AfterFunc

方法定义:

func AfterFunc(d Duration, f func()) *Timer

  time.AfterFunc参数为超时时间d和一个具体的函数f,返回一个Timer的指针,作用在创建出timer之后,在当前goroutine,等待一段时间d之后,将执行f
使用示例:

package mainimport ("fmt""time"
)func main() {duration := time.Duration(1) * time.Secondf := func() {fmt.Println("f has been called after 1s by time.AfterFunc")}timer := time.AfterFunc(duration, f)defer timer.Stop()time.Sleep(2 * time.Second)
}

运行结果:  1s之后打印语句。

f has been called after 1s by time.AfterFunc

time.After

方法定义:

func After(d Duration) <-chan Time {return NewTimer(d).C
}

        根据函数定义可以看到,after函数会返回timer里的管道,并且这个管道会在经过时段d之后写入数据,调用这个函数,就相当于实现了定时器。一般time.After会配合select一起使用

        使用示例如下: 

package mainimport ("fmt""time"
)func main() {ch := make(chan string)go func() {time.Sleep(time.Second * 3)ch <- "test"}()select {case val := <-ch:fmt.Printf("val is %s\n", val)case <-time.After(time.Second * 2):fmt.Println("timeout!!!")}
}

运行结果:

timeout!!!

        程序创建了一个管道ch,并且在主goroutineselect监听两个管道,一个是刚刚创建的ch,一个是time.After函数返回的管道cch管道3s之后才会有数据写入,而time.After函数是2s超时,所以2s后就会有数据写入,这样select会先收到管道c里的数据,执行timeout退出。 

Ticker

Ticker结构定义

type Ticker struct {C <-chan Time // The channel on which the ticks are delivered.r runtimeTimer
}

  Ticker对象的字段和Timer是一样的,也包含一个通道字段,并会每隔时间段d就向该通道发送当时的时间,根据这个管道消息来触发事件,但是ticker只要定义完成,就从当前时间开始计时,每隔固定时间都会触发,只有关闭Ticker对象才不会继续发送时间消息。 

创建Ticker

方法定义如下:

func NewTicker(d Duration) *Ticker

NewTicker用于返回一个Ticker对象。 
使用示例:

package mainimport ("fmt""time"
)func Watch() chan struct{} {ticker := time.NewTicker(1 * time.Second)ch := make(chan struct{})go func(ticker *time.Ticker) {defer ticker.Stop()for {select {case <-ticker.C:fmt.Println("watch!!!")case <-ch:fmt.Println("Ticker Stop!!!")return}}}(ticker)return ch
}func main() {ch := Watch()time.Sleep(5 * time.Second)ch <- struct{}{}close(ch)
}

运行结果:

watch!!!
watch!!!
watch!!!
watch!!!
watch!!!
Ticker Stop!!!

  Watch函数里创建一个ticker,将它传递到子goroutine函数,每隔1s打印"watch!!!",主函数创建一个管道ch,通过ch来控制go func()函数的退出,在5s之后主函数发送一个信号到chwatch函数select收到ch信号,将return,在return之前将执行defer ticker.Stop()语句关闭ticker。在这5s之间,select将每个1s收到ticker.C管道里的消息,打印"watch!!!"。

注意:调用ticker.Stop()只会停止ticker,但并不会关闭ticker.C这个管道,所以我们需要用这个channel来控制watch函数中的goroutine能够退出。

http://www.xdnf.cn/news/17028.html

相关文章:

  • 数据结构---Makefile 文件(格式、文件变量、调用、伪目标)、gcc编译的四个步骤、双向链表(概念、作用、应用)
  • Android 之 Kotlin中的kapt
  • 风丘助力混合动力汽车工况测试:精准采集整车信号解决方案
  • 【Spring Cloud】-- 注册中心
  • K8S的NetworkPolicy使用教程
  • 【taro react】 ---- useModel 数据双向绑定 hook 实现
  • 12306旅游产品数据抓取:Python+API逆向分析
  • Webpack 5 Module Federation 模块共享最佳实践
  • 【学习笔记】FTP库函数学习
  • 基于铁头山羊STM32的平衡车电机转速开环闭环matlab仿真
  • [Linux]学习笔记系列 -- [arm]boot
  • 如何在 FastAPI 中优雅处理后台任务异常并实现智能重试?
  • Anthropic的商业模式与战略
  • 如何基于MQ实现分布式事务
  • 电子电气架构 ---智能电动汽车嵌入式软件开发过程中的block点
  • PostgreSQL——数据类型和运算符
  • 深度残差网络ResNet结构
  • 《Leetcode》-面试题-hot100-子串
  • 【unitrix】 7.1 二进制位加法(bit_add.rs)
  • 规则方法关系抽取-笔记总结
  • 县级融媒体中心备份与恢复策略(精简版3-2-1架构)
  • 文件包含篇
  • 秋招笔记-8.4
  • Java基础学习(一):类名规范、返回值、注释、数据类型
  • C++面试题及详细答案100道( 01-10 )
  • 【数据结构】排序(sort) -- 插入排序
  • 【深度学习新浪潮】近三年城市级数字孪生的研究进展一览
  • 【数据结构入门】链表
  • Vue3核心语法进阶(生命周期)
  • 【教学类-52-17】20250803动物数独_空格尽量分散_只有一半关卡数(N宫格通用版3-10宫格)0图、1图、2图、6图、有答案、无答案 组合版24套