learning_notes

学习笔记

View project on GitHub

timer的使用

timer的调度

如何存储

  • Go 1.9 版本之前,所有的计时器由全局唯一的四叉堆维护,协程间竞争激烈。
  • Go 1.10 - 1.13,全局使用 64 个四叉堆维护全部的计时器,没有本质解决 1.9 版本之前的问题。
  • Go 1.14 版本之后,每个 P 单独维护一个四叉堆。

使用的问题

  • 错误创建很多的 timer,导致资源浪费。
    func main() {
      for {
          // xxx 一些操作
          timeout := time.After(30 * time.Second) // timer.After 底层是调用的 timer.NewTimer
          select {
          case <- someDone:
              // do something
          case <-timeout:
              return
          }
      }
    }
    // 解决办法: 使用 time.Reset 重置 timer,重复利用 timer。
    
  • 由于 Stop 时不会主动关闭 C,导致程序阻塞。
    func main() {
      timer1 := time.NewTimer(2 * time.Second)
      go func() {
          timer1.Stop()
      }()
      <-timer1.C //  goroutine 泄露,内存泄露
    
      println("done")
    }