Golang 并发编程(四): 定时器 与 断续器
- 陈大剩
- 2025-01-26 00:19:19
- 845

Time 包与 channel
断续器 语言中标准库包 time 中的一些 API 是用通道辅助实现的,这些 API 可以帮助我们更好的了解通道的发送和接收操作,更加有效的控制发送和接收操作。所以本节是 Golang 中 Golang 中 Channel 节拓展篇。
定时器
定时器是 time 包中结构体 Timer 类型,time 包中有两个函数能够帮助我们构建 time.Timer 类型的值,它们是 time.NewTimer 函数和 time.AfterFunc 函数。这两个函数非常简单,只需要调用时传递一个 time.Duration 类型的值就可以了。这个唯一参数就是从定时器被初始化的那一刻起,距离到期时间需要多少纳秒(ns)。在 time.Timer 类型中,对外通知定时器到期的途径就是通道,由字段 C 代表,C 本是双向通道,C 在赋值时自动转为了接收通道。
func main() {
t := time.NewTimer(time.Second * 3)
fmt.Printf("当前时间:%v \n", time.Now())
exp := <-t.C
fmt.Printf("失效时间:%v \n", exp)
fmt.Printf("结束时间:%v \n", t.Stop())
}
使用定时器可以便捷的实现接收操作的超时设定,例如:
intChan := make(chan int, 1)
go func() {
time.Sleep(time.Second)
intChan <- 1
}()
select {
case i := <-intChan:
fmt.Printf("接收到元素的值:%v\n", i)
case <-time.NewTimer(time.Millisecond * 500).C:
fmt.Println("已经超时")
}
根据上述例子,我们很容易想到定时器用来当自旋锁最适合不过了。因为定时器是引用类型,所以定时器也可以重复使用:
intChan := make(chan int, 1)
go func() {
for i := 0; i < 5; i++ {
time.Sleep(time.Second)
intChan <- i
}
close(intChan)
}()
timeout := time.Millisecond * 500
var timer *time.Timer
for {
if timer == nil {
timer = time.NewTimer(timeout)
} else {
timer.Reset(timeout)
}
select {
case i, ok := <-intChan:
if !ok {
fmt.Println("结束")
return
}
fmt.Printf("接收到元素的值:%v\n", i)
case <-timer.C:
fmt.Println("已经超时")
}
}
这里只介绍了 time.NewTimer 函数,具体 time.AfterFunc 函数可自行了解。
提示:如果厌倦了
timer.C可以直接使用 ``time.After` 即可。
断续器
time 包中另一个重要的结构体类型是 time.Ticker。它表示了断续器的静态结构,包含的字段和 time.Timer 一致,但行为却大不相同。定时器在重置之前只会到期一次,而断续器则会在立马到期后进入下一个周期并等待再次到期,周而复始,直到停止。
intChan := make(chan int, 1)
ticker := time.NewTicker(time.Second)
go func() {
for _ = range ticker.C {
select {
case intChan <- 1:
case intChan <- 2:
case intChan <- 3:
}
}
close(intChan)
fmt.Println("结束发送")
}()
var sum int
for v := range intChan {
fmt.Printf("读取到值:%v \n", v)
sum += v
if sum > 10 {
fmt.Println("大于 10 结束")
break
}
}
fmt.Println("结束接收")
上述程序中,发送方会用断续器 ticker 每隔 1 s 向 intChan 通道发送一个范围为 [1,3] 的随机数字,这个发送不会主动停止。接收方一直累加到 10 时停止(主 goroutine 结束方式)。
总结
定时器 和 断续器 都是充分利用了缓冲通道的异步特性来传达到期通知,定时器 可以用来做超时时间设计,而 断续器 可以做一些定时任务相关的设计。













