- 定时器 秀才 2025年2月14日 大约 6 分钟 Go语言 Go语言 golang go进阶 定时器 并发 此页内容 1. Timer 1.1 Timer的结构定义 1.2 创建Timer 1.3 停止Timer 1.4 重置Timer 1.5 time.AfterFunc 1.6 time.After 2. Ticker 2.1 Ticker创建 2.2 Ticker对象定义 在我们项目中,常常会有这样的场景,比如到了未来某一时刻,需要某个逻辑或者某个任务执行一次,或者是周期性的的执行多次,有点类似定时任务。这种场景就需要用到定时器,Go语言中也内置了定时器的实现, timer 和 ticker 。 1. Timer Timer 是一种一次性时间定时器,即在未来某个时刻,触发的事件只会执行一次。 1.1 Timer的结构定义
type Timer struct {
C <-chan Time
r runtimeTimer
}
Timer 结构里有一个 Time 类型的管道 C ,主要用于事件通知。在未到达设定时间的时候,管道内没有数据写入,一直处于阻塞状态,到达设定时间后,会向管道内写入一个系统时间,触发事件。 1.2 创建Timer
func NewTimer(d Duration) *Timer
使用示例:
package main
import (
"fmt"
"time"
)
func main() {
timer := time.NewTimer(2 * time.Second) //设置超时时间2s
<-timer.C
fmt.Println("after 2s Time out!")
}
运行结果:
after 2s Time out!
程序在 2s 后打印 "after 2s Time out!" ,因为创建了一个定时器 timer ,设置了超时时间为 2s ,执行 <-timer.C 会一直阻塞,直到 2s 后,程序继续执行。 1.3 停止Timer
func (t *Timer) Stop() bool
返回值: true :执行 stop() 时 timer 还没有到达超时时间,即超时时间内停止了 timer false :执行 stop() 时 timer 到达了超时时间,过了超时时间才停止 timer 使用示例:
package main
import (
"fmt"
"time"
)
func main() {
timer := time.NewTimer(2 * time.Second) //设置超时时间2s
res := timer.Stop()
fmt.Println(res)
}
运行结果:
true
1.4 重置Timer
func (t *Timer) Reset(d Duration) bool
对于已经过期或者是已经停止的 timer ,可以通过重置方法激活使其继续生效。 使用示例:
package main
import (
"fmt"
"time"
)
func main() {
timer := time.NewTimer(time.Second * 2)
<-timer.C
fmt.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 。 1.5 time.AfterFunc 方法定义:
func AfterFunc(d Duration, f func()) *Timer
time.AfterFunc 参数为超时时间 d 和一个具体的函数 f ,返回一个 Timer 的指针,作用在创建出 timer 之后,在当前 goroutine ,等待一段时间 d 之后,将执行 f 。 使用示例:
package main
import (
"fmt"
"time"
)
func main() {
duration := time.Duration(1) * time.Second
f := 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)
}
运行结果:
f has been called after 1s by time.AfterFunc
1s之后打印语句。 1.6 time.After 方法定义:
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
根据函数定义可以看到, after 函数会返回 timer 里的管道,并且这个管道会在经过时段 d 之后写入数据,调用这个函数,就相当于实现了定时器。一般 time.After 会配合 select 一起使用,使用示例如下:
package main
import (
"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 ,并且在主 goroutine 用 select 监听两个管道,一个是刚刚创建的 ch ,一个是 time.After 函数返回的管道 c , ch 管道3s之后才会有数据写入,而 time.After 函数是2s超时,所以2s后就会有数据写入,这样 select 会先收到管道 c 里的数据,执行 timeout 退出。 2. Ticker 2.1 Ticker创建 方法定义如下:
func NewTicker(d Duration) *Ticker
NewTicker 用于返回一个 Ticker 对象。 2.2 Ticker对象定义
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
r runtimeTimer
}
Ticker 对象的字段和 Timer 是一样的,也包含一个通道字段,并会每隔时间段 d 就向该通道发送当时的时间,根据这个管道消息来触发事件,但是 ticker 只要定义完成,就从当前时间开始计时,每隔固定时间都会触发,只有关闭 Ticker 对象才不会继续发送时间消息。 使用示例:
package main
import (
"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之后主函数发送一个信号到 ch , watch 函数 select 收到 ch 信号,将 return ,在 return 之前将执行 defer ticker.Stop() 语句关闭 ticker 。在这5s之间, select 将每个1s收到 ticker.C 管道里的消息,打印"watch!!!"。 注意:调用 ticker.Stop() 只会停止 ticker ,但并不会关闭 ticker.C 这个管道,所以我们需要用这个 channel 来控制 watch 函数中的 goroutine 能够退出。 关注秀才公众号: IT杨秀才 ,领取精品学习资料 公众号后台回复: Go面试 ,领取Go面试题库PDF 公众号后台回复: Go学习 ,领取Go必看书籍 公众号后台回复: 大模型 ,领取大模型学习资料 公众号后台回复: 111 ,领取架构学习资料 公众号后台回复: 26届秋招 ,领取26届秋招企业汇总表
🔥 配套实战项目,拆得开、跑得起、能写进简历 多 Agent 编排 + RAG 混合检索 · 31 篇深度教程 + 50+ 面试题 点击查看 DevSupport AI 实战项目 → 在 GitHub 上编辑此页 上次编辑于: 2026/6/24 23:41:22 贡献者: Percygu , Your Name , gupeng 上一页 6. Context 下一页 8. 协程池