使用time.AfterFunc在golang中按间隔执行重复任务,这只是一个示例。

huangapple go评论109阅读模式
英文:

do repetitive tasks at intervals in golang using time.AfterFunc, just a sample

问题

我只需要翻译代码部分,以下是翻译好的内容:

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

但是如果一切正常,至少会调用该函数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)
}
英文:

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 (
&quot;fmt&quot;
&quot;time&quot;
&quot;os&quot;
&quot;os/signal&quot;
)
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 &lt;- 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 &lt;-closeSig:
return
case call := &lt;-this.TimeCall.Queue:
call.CallBack()
}
}
}
func main() {
var closeChan chan bool
InsPipeService := &amp;PipeService{TimeCall: NewTimer(10)}
InsPipeService.IntervalCall(2*time.Second,func(){
fmt.Println(&quot;interval call&quot;)
})
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

答案1

得分: 6

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

> Timer 类型表示一个单一事件。当计时器到期时,当前时间将被发送到 C 通道,除非计时器是由 AfterFunc 创建的。

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

还要注意,你将 2 作为 PipeService.IntervalCall() 方法的间隔传递。这个 interval 参数的类型是 time.Duration。所以当你传递 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)
}
英文:

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(&quot;interval call&quot;)
})

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(&quot;tick&quot;, 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(&quot;tick&quot;, now)
}

答案2

得分: 0

设置时间间隔,然后调用Start函数,它将在每个时间间隔上运行用户的任务。将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()
	}
}

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

//用户代码:
var n int = 5
var it *IntervalTimer

func uerTask() {
	fmt.Println(n, time.Now()) // 执行用户任务...
	n--
	if n == 0 {
		it.Enabled = false
	}
}
func main() {
	it = &IntervalTimer{Interval: 500 * time.Millisecond, Enabled: true, Job: uerTask}
	it.Start()

	//做一些其他任务...
	it.Wg.Wait()
	fmt.Println("再见")
}

希望对你有帮助!

英文:

set time interval then call Start it will run user Job on each time intervals. set Enabled to false to stop it.
My Sample:

package main
import (
&quot;fmt&quot;
&quot;sync&quot;
&quot;time&quot;
)
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 = &amp;IntervalTimer{Interval: 500 * time.Millisecond, Enabled: true, Job: uerTask}
it.Start()
//do some job ...
it.Wg.Wait()
fmt.Println(&quot;Bye&quot;)
}

huangapple
  • 本文由 发表于 2016年4月27日 18:02:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/36886548.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定