使用 time.AfterFunc 在 golang 中每隔一段时间执行重复任务,只是一个示例

tim*_*tee 1 go

我只想在 Go 中使用 time.AfterFunc 执行重复的后台任务,但逻辑似乎有问题。输出只是:间隔调用间隔调用

但如果一切正常的话,至少要调用该函数 5 次。

package main

import (
    "fmt"
    "time"
    "os"
    "os/signal"
)

type Timer struct {
    Queue chan *TimeCall
}

func NewTimer(l int) *Timer {
    timer := new(Timer)
    timer.Queue = make(chan *TimeCall,l)
    return timer
}

type TimeCall struct {
    timer    *time.Timer
    callback func()
}

func (this *TimeCall) CallBack() {
    defer func() { recover() }()
    if this.callback != nil {
        this.callback()
    }
}

func (this *Timer) AfterFunc(d time.Duration, callback func()) *TimeCall {
    call := new(TimeCall)
    call.callback = callback
    call.timer = time.AfterFunc(d, func() {
        this.Queue <- call
    })
    return call
}



type PipeService struct {
    TimeCall *Timer
}

func (this *PipeService) AfterFunc(delay time.Duration, callback func()) *TimeCall {
    return this.TimeCall.AfterFunc(delay, callback)
}

func (this *PipeService) IntervalCall(interval time.Duration, callback func()) {
    this.TimeCall.AfterFunc(interval,func(){
        if callback != nil {
            callback()
        }
        this.AfterFunc(interval,callback)
    })
}

func (this *PipeService) Run(closeSig chan bool) {
    for {
        select {
        case <-closeSig:
            return
        case call := <-this.TimeCall.Queue:
            call.CallBack()
        }
    }
}

func main() {
    var closeChan chan bool
    InsPipeService := &PipeService{TimeCall: NewTimer(10)}
    InsPipeService.IntervalCall(2*time.Second,func(){
        fmt.Println("interval call")
    })

    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, os.Kill)

    go func(){
        InsPipeService.Run(closeChan)
    }()

    time.Sleep(10*time.Second)
}
Run Code Online (Sandbox Code Playgroud)

运行代码

icz*_*cza 6

time.AfterFunc()返回 a *time.Timer,引用其文档:

Timer 类型代表单个事件。当Timer到期时,当前时间将在C上发送,除非Timer是由AfterFunc创建的。

返回time.Timer的值time.AfterFunc()不会重复,所以你看到的完全正常:在你中PipeService.IntervalCall()你立即执行回调,并在超时后执行。

另请注意,您2作为该方法的间隔传递PipeService.IntervalCall()。该interval参数的类型为time.Duraion。所以当你通过 时2,那不会是 2 秒(但实际上是 2 纳秒)。您应该传递一个由包中的常量构造的值,time例如:

InsPipeService.IntervalCall(2 * time.Second, func(){
    fmt.Println("interval call")
})
Run Code Online (Sandbox Code Playgroud)

如果您想重复,请使用time.Ticker. 例如,以下代码每 2 秒打印一条消息:

t := time.NewTicker(2 * time.Second)
for now := range t.C {
    fmt.Println("tick", now)
}
Run Code Online (Sandbox Code Playgroud)

或者只是如果您不需要Ticker并且不想将其关闭:

c := time.Tick(2 * time.Second)
for now := range c {
        fmt.Println("tick", now)
}
Run Code Online (Sandbox Code Playgroud)