我只想在 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)
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)