dro44817 2016-04-27 10:02
浏览 175
已采纳

使用time在golang中间隔执行重复性任务。

I just want to do repetitive background tasks in Go, using time.AfterFunc,But seems something wrong with the logic. The out put just: interval call interval call

But at least 5 times to call the function if all things went normal.

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条回答 默认 最新

  • doushifen4060 2016-04-27 10:45
    关注

    time.AfterFunc() returns a *time.Timer, quoting form its doc:

    The Timer type represents a single event. When the Timer expires, the current time will be sent on C, unless the Timer was created by AfterFunc.

    The time.Timer returned by time.AfterFunc() does not repeat, so what you see is perfectly normal: in your PipeService.IntervalCall() you execute the callback immediately, and it gets executed after the timeout.

    Also note that you pass 2 as interval for the PipeService.IntervalCall() method. This interval parameter is of type time.Duraion. So when you pass 2, that won't be 2 seconds (but actually 2 nanoseconds). You should pass a value constructed from constants from the time package like:

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

    If you want repetition, use time.Ticker. For example the following code prints a message in every 2 seconds:

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

    Or simply if you don't need the Ticker and you don't want to shut it down:

    c := time.Tick(2 * time.Second)
    for now := range c {
            fmt.Println("tick", now)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 luckysheet
  • ¥15 ZABBIX6.0L连接数据库报错,如何解决?(操作系统-centos)
  • ¥15 找一位技术过硬的游戏pj程序员
  • ¥15 matlab生成电测深三层曲线模型代码
  • ¥50 随机森林与房贷信用风险模型
  • ¥50 buildozer打包kivy app失败
  • ¥30 在vs2022里运行python代码
  • ¥15 不同尺寸货物如何寻找合适的包装箱型谱
  • ¥15 求解 yolo算法问题
  • ¥15 虚拟机打包apk出现错误