自学内容网 自学内容网

【Go - 定时器知多少,4种常见场景】

Go 语言中有几种方式可以实现定时执行逻辑,主要通过 time 包提供的 TimerTicker 来实现。

1 - 延时执行

1.1 使用 time.Timer 实现一次性定时任务

time.Timer 用于在未来某一时刻执行一次任务。以下是一个示例:

package main

import (
"fmt"
"time"
)

func main() {
timer := time.NewTimer(2 * time.Second) // 创建一个定时器,设置时间为2秒后
currtime := <-timer.C                   // 阻塞直到定时器的通道 C 发送了定时事件
fmt.Println("Current time:", currtime)
fmt.Println("Timer expired")
}

这里解释下,<-timer.C

在Go语言中,<-timer.C 是一个通道(channel)接收操作,用于从定时器的C通道接收消息。这里的timer.Ctime.Timer类型的一个属性,它是一个通道(channel),类型为<-chan Time。当定时器到期时,当前时间会被发送到C通道。具体来说,<-timer.C执行以下操作:

  1. 阻塞当前goroutine:当前的goroutine会在这一行代码处阻塞,直到timer.C通道中有值可以接收。
  2. 接收通道值:定时器到期后,会向C通道发送一个time.Time类型的值,表示当前时间。这个操作会接收该值,并存到currtime里。
  3. 继续执行:接收到值后,阻塞解除,程序继续执行下一行代码,即打印"Timer expired"。

简而言之,<-timer.C在这里用于等待定时器timer的到期事件。

1.2 使用 time.AfterFunc 实现延迟执行

time.AfterFunc 用于在未来某一时刻执行一次任务,但它允许你指定一个回调函数,当定时器到期时,这个函数将被调用。这对于需要延迟执行某些操作非常有用。

package main

import (
    "fmt"
    "time"
)

func main() {
    time.AfterFunc(2*time.Second, func() {
        fmt.Println("Timer expired")
    })

    // 等待足够的时间以看到定时器到期的消息
    time.Sleep(3 * time.Second)
}

2 - 周期执行

2.1 使用 time.Ticker 实现周期性定时任务

time.Ticker 用于周期性执行任务。示例代码,

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(1 * time.Second) // 创建一个定时器,设置周期为1秒
    go func() {
        for t := range ticker.C {
            fmt.Println("Tick at", t)
            // process something
        }
    }()

    // 在100秒后停止定时器
    time.Sleep(100 * time.Second)
    ticker.Stop()
    fmt.Println("Ticker stopped")
}

但是注意 上面周期性定时任务,有时并不准时,例如当 定时任务里面有同步的耗时处理,且耗时时间超过时间间隔,则会影响下一次定时任务的启动。

2.2 每次要等上一次执行完,在执行下一次

有些周期性定时任务,是要依次执行,上一次执行完,才可以执行下一次。 执行模型如下,

示例代码

package main

import (
"fmt"
"time"
)

func process() {
// do something.
timer := time.NewTimer(5 * time.Second)
currtime := <-timer.C
fmt.Println("Current time:", currtime)
}

func loopDelayAtleastNSec(n int) {
time.AfterFunc(time.Duration(n)*time.Second, func() {
fmt.Println("Processing ...")
process()
fmt.Println("Process done")
loopDelayAtleastNSec(n)
})
}

func main() {
interval := 2
loopDelayAtleastNSec(interval)

// 创建一个空的通道, 阻塞住
block := make(chan struct{})
<-block
}

结语

这些方法提供了灵活的方式来处理在 Go 程序中的定时任务。选择哪种方式取决于你的具体需求,比如是一次性延时执行、重复执行还是需要延迟调用。


原文地址:https://blog.csdn.net/qq_38428433/article/details/140739082

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!