陈大剩博客

Golang 并发编程(四): 定时器 与 断续器

  • 陈大剩
  • 2025-01-26 00:19:19
  • 160

golang 标题

Time 包与 channel

断续器 语言中标准库包 time 中的一些 API 是用通道辅助实现的,这些 API 可以帮助我们更好的了解通道的发送和接收操作,更加有效的控制发送和接收操作。所以本节是 GolangGolang 中 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 结束方式)。

总结

定时器断续器 都是充分利用了缓冲通道的异步特性来传达到期通知,定时器 可以用来做超时时间设计,而 断续器 可以做一些定时任务相关的设计。

分享到:
0

说点儿什么吧

头像

表情

本站由陈大剩博客程序搭建 | 湘ICP备2023000975号| Copyright © 2017 - 陈大剩博客 | 本站采用创作共用版权:CC BY-NC 4.0

站长统计| 文章总数[124]| 评论总数[11]| 登录用户[26]| 时间点[128]

logo

登入

社交账号登录