在golang中使用time.AfterFunc定期执行重复性任务,只是一个样本

时间:2016-04-27 10:02:00

标签: 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

2 个答案:

答案 0 :(得分:2)

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

  

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

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

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

InsPipeService.IntervalCall(2 * time.Second, func(){
    fmt.Println("interval call")
})

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

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

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

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

答案 1 :(得分:0)

设置时间间隔然后调用Start它将在每个时间间隔运行用户Job。将Enabled设置为false以停止它 我的样本:

package main

import (
    "fmt"
    "sync"
    "time"
)

type IntervalTimer struct {
    Interval time.Duration
    Enabled  bool
    Job      func()
    Wg       sync.WaitGroup
}

func (it *IntervalTimer) isr() {
    if it.Enabled {
        it.Job()
        time.AfterFunc(it.Interval, it.isr)
    } else {
        it.Wg.Done()
    }
}

//trigger
func (it *IntervalTimer) Start() {
    if it.Enabled {
        it.Wg.Add(1)
        time.AfterFunc(it.Interval, it.isr)
    }
}

// user code:
var n int = 5
var it *IntervalTimer

func uerTask() {
    fmt.Println(n, time.Now()) // do user job ...
    n--
    if n == 0 {
        it.Enabled = false
    }
}
func main() {
    it = &IntervalTimer{Interval: 500 * time.Millisecond, Enabled: true, Job: uerTask}
    it.Start()

    //do some job ...
    it.Wg.Wait()
    fmt.Println("Bye")
}