【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 程序中的定时任务。选择哪种方式取决于你的具体需求,比如是一次性延时执行、重复执行还是需要延迟调用。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值