Is there a way to do repetitive background tasks in Go? I'm thinking of something like Timer.schedule(task, delay, period)
in Java. I know I can do this with a goroutine and Time.sleep()
, but I'd like something that easily stopped.
Here's what I got, but looks ugly to me. Is there a cleaner/better way?
func oneWay() {
var f func()
var t *time.Timer
f = func () {
fmt.Println("doing stuff")
t = time.AfterFunc(time.Duration(5) * time.Second, f)
}
t = time.AfterFunc(time.Duration(5) * time.Second, f)
defer t.Stop()
//simulate doing stuff
time.Sleep(time.Minute)
}
转载于:https://stackoverflow.com/questions/16466320/is-there-a-way-to-do-repetitive-tasks-at-intervals-in-golang
The function time.NewTicker
makes a channel that sends a periodic message, and provides a way to stop it. Use it something like this (untested):
ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
for {
select {
case <- ticker.C:
// do stuff
case <- quit:
ticker.Stop()
return
}
}
}()
You can stop the worker by closing the quit
channel: close(quit)
.
How about something like
package main
import (
"fmt"
"time"
)
func schedule(what func(), delay time.Duration) chan bool {
stop := make(chan bool)
go func() {
for {
what()
select {
case <-time.After(delay):
case <-stop:
return
}
}
}()
return stop
}
func main() {
ping := func() { fmt.Println("#") }
stop := schedule(ping, 5*time.Millisecond)
time.Sleep(25 * time.Millisecond)
stop <- true
time.Sleep(25 * time.Millisecond)
fmt.Println("Done")
}
Check out this library: https://github.com/robfig/cron
Example as below:
c := cron.New()
c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("@hourly", func() { fmt.Println("Every hour") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
c.Start()
If you do not care about tick shifting (depending on how long did it took previously on each execution) and you do not want to use channels, it's possible to use native range function.
i.e.
package main
import "fmt"
import "time"
func main() {
go heartBeat()
time.Sleep(time.Second * 5)
}
func heartBeat(){
for range time.Tick(time.Second *1){
fmt.Println("Foo")
}
}
If you want to stop it in any moment ticker
ticker := time.NewTicker(500 * time.Millisecond)
go func() {
for range ticker.C {
fmt.Println("Tick")
}
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
If you do not want to stop it tick:
tick := time.Tick(500 * time.Millisecond)
for range tick {
fmt.Println("Tick")
}
I use the following code:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("\nToday:", now)
after := now.Add(1 * time.Minute)
fmt.Println("\nAdd 1 Minute:", after)
for {
fmt.Println("test")
time.Sleep(10 * time.Second)
now = time.Now()
if now.After(after) {
break
}
}
fmt.Println("done")
}
It is more simple and works fine to me.
package main
import (
"github.com/jasonlvhit/gocron"
"github.com/sirupsen/logrus"
"time"
)
func main() {
s := gocron.NewScheduler()
s.Every(15).Seconds().Do(cron)
<-s.Start()
}
func cron() {
log := logrus.WithFields(logrus.Fields{
"key": "15",
"datatime": time.Now().Unix(),
})
log.WithFields(logrus.Fields{"data": 10}).Info("hello world!")
}