Go进阶之定时器Ticker的实现示例

Written by

in

文章目录
  • func main() { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for range ticker.C { log.Println(“tick”) } } 执行结果: 定时聚合任务: 示例: func TickerLaunch() { //5分钟执行一次. ticker := time.NewTicker(5 * time.Minute) defer ticker.Stop() maxPassenger := 30 passengers := make([]string, 0, maxPassenger) for { passenger := GetNewPassenger() if passenger != “” { passengers = append(passengers, passenger) } else { time.Sleep(1 * time.Second) } select { case <-ticker.C: Launch(passengers) passengers = []string{} default: if len(passengers) >= maxPassenger { Launch(passengers) passengers = []string{} } } } } func Launch(passengers []string) { for i := range passengers { fmt.Println(passengers[i], “发车了”) } } func GetNewPassenger() string { return “乘客” }
  • 1)创建定时器: 源码位置:src/time/tick.go func NewTicker(d Duration) *Ticker { if d <= 0 { panic(“non-positive interval for NewTicker”) } // Give the channel a 1-element time buffer. // If the client falls behind while reading, we drop ticks // on the floor until the client catches up. c := make(chan Time, 1) t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c)))) t.C = c return t } 2).停止定时器: 源码位置:src/time/tick.go // Stop turns off a ticker. After Stop, no more ticks will be sent. // Stop does not close the channel, to prevent a concurrent goroutine // reading from the channel from seeing an erroneous “tick”. func (t *Ticker) Stop() { if !t.initTicker { // This is misuse, and the same for time.Timer would panic, // but this didn’t always panic, and we keep it not panicking // to avoid breaking old programs. See issue 21874. return } stopTimer((*Timer)(unsafe.Pointer(t))) } 流程图: 总流程图:
  • 在有些场景下.启动一个定时器后.该定时器永远不会停止.比如定时轮询任务.此时可 以使用一个简单的Tick函数来获取定时器的管道.函数如下: 源码位置:src/runtime/tick.go func Tick(d Duration) <-chan Time { if d <= 0 { return nil } return NewTicker(d).C } 从源码可以看出其实是创建了一个Ticker.然后只返回了管道.并没有返回ticker.所以 没有办法停止.
  • 当Ticker用于for循环时.很容易出现意想不到的资源泄漏问题. 示例: func WrongTicker() { for { select { case <-time.Tick(time.Second): log.Printf(“resource leak!”) } } } 上面的代码.select每次检测case语句都会创建一个定时器.for循环又会不断的执行 select语句.系统里会有越来越多的定时器不断地消耗CPU资源.最终CPU资源被耗 到此这篇关于Go进阶之定时器Ticker的实现示例的文章就介绍到这了,更多相关Go 定时器Ticker内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Go语言定时器Timer和Ticker的使用与区别 Golang定时器Timer与Ticker的使用详解 Go Ticker 周期性定时器用法及实现原理详解 go语言定时器Timer及Ticker的功能使用示例详解 Golang 定时器(Timer 和 Ticker),这篇文章就够了
  • 目录
    • 1.简单定时任务:
    • 2.Ticker对外接口:
    • 3.简单接口:
    • 4.错误示例:

    Ticker是周期性定时器.即周期性的触发一个事件.通过Ticker本身提供的管道将事件

    传递出去.

    Ticker数据结构:

    源码位置:src/time/tick.go

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

    Ticker对外仅暴露了一个channel.当指定时间到来时就往该channel中写入系统时

    间.即一个事件.

    func main() {
        ticker := time.NewTicker(1 * time.Second)
    
        defer ticker.Stop()
    
        for range ticker.C {
           log.Println("tick")
        }
    }
    

    执行结果:

    定时聚合任务:

    示例:

    func TickerLaunch() {
        //5分钟执行一次.
        ticker := time.NewTicker(5 * time.Minute)
    
        defer ticker.Stop()
        maxPassenger := 30
        passengers := make([]string, 0, maxPassenger)
        for {
           passenger := GetNewPassenger()
           if passenger != "" {
              passengers = append(passengers, passenger)
           } else {
              time.Sleep(1 * time.Second)
           }
           select {
           case <-ticker.C:
              Launch(passengers)
              passengers = []string{}
           default:
              if len(passengers) >= maxPassenger {
                 Launch(passengers)
                 passengers = []string{}
              }
           }
        }
    }
    
    func Launch(passengers []string) {
        for i := range passengers {
           fmt.Println(passengers[i], "发车了")
        }
    }
    
    func GetNewPassenger() string {
        return "乘客"
    }
    

    1)创建定时器:

    源码位置:src/time/tick.go

    func NewTicker(d Duration) *Ticker {
        if d <= 0 {
           panic("non-positive interval for NewTicker")
        }
        // Give the channel a 1-element time buffer.
        // If the client falls behind while reading, we drop ticks
        // on the floor until the client catches up.
        c := make(chan Time, 1)
        t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c))))
        t.C = c
        return t
    }
    

    2).停止定时器:

    源码位置:src/time/tick.go

    // Stop turns off a ticker. After Stop, no more ticks will be sent.
    // Stop does not close the channel, to prevent a concurrent goroutine
    // reading from the channel from seeing an erroneous "tick".
    func (t *Ticker) Stop() {
        if !t.initTicker {
           // This is misuse, and the same for time.Timer would panic,
           // but this didn't always panic, and we keep it not panicking
           // to avoid breaking old programs. See issue 21874.
           return
        }
        stopTimer((*Timer)(unsafe.Pointer(t)))
    }
    

    流程图:

    总流程图:

    在有些场景下.启动一个定时器后.该定时器永远不会停止.比如定时轮询任务.此时可

    以使用一个简单的Tick函数来获取定时器的管道.函数如下:

    源码位置:src/runtime/tick.go

    func Tick(d Duration) <-chan Time {
        if d <= 0 {
           return nil
        }
        return NewTicker(d).C
    }
    

    从源码可以看出其实是创建了一个Ticker.然后只返回了管道.并没有返回ticker.所以

    没有办法停止.

    当Ticker用于for循环时.很容易出现意想不到的资源泄漏问题.

    示例:

    func WrongTicker() {
        for  {
           select {
           case <-time.Tick(time.Second):
              log.Printf("resource leak!")
           }
        }
    }
    

    上面的代码.select每次检测case语句都会创建一个定时器.for循环又会不断的执行

    select语句.系统里会有越来越多的定时器不断地消耗CPU资源.最终CPU资源被耗

    到此这篇关于Go进阶之定时器Ticker的实现示例的文章就介绍到这了,更多相关Go 定时器Ticker内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • Go语言定时器Timer和Ticker的使用与区别
    • Golang定时器Timer与Ticker的使用详解
    • Go Ticker 周期性定时器用法及实现原理详解
    • go语言定时器Timer及Ticker的功能使用示例详解
    • Golang 定时器(Timer 和 Ticker),这篇文章就够了

    站内搜索