Existe-t-il un moyen d'effectuer des tâches d'arrière-plan répétitives dans Go? Je pense à quelque chose comme Timer.schedule(task, delay, period)
en Java. Je sais que je peux le faire avec un goroutine et Time.sleep()
, mais j'aimerais quelque chose qui s'arrête facilement.
Voici ce que j'ai, mais me semble moche. Y a-t-il un moyen plus propre/meilleur?
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)
}
La fonction time.NewTicker
crée un canal qui envoie un message périodique et fournit un moyen de l'arrêter. Utilisez-le comme ceci (non testé):
_ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
for {
select {
case <- ticker.C:
// do stuff
case <- quit:
ticker.Stop()
return
}
}
}()
_
Vous pouvez arrêter le travailleur en fermant le canal quit
: close(quit)
.
Que diriez-vous de quelque chose comme
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")
}
Si vous ne vous souciez pas du décalage des ticks (en fonction du temps écoulé auparavant à chaque exécution) et que vous ne souhaitez pas utiliser de canaux, il est possible d'utiliser la fonction de plage native.
c'est à dire.
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")
}
}
Découvrez cette bibliothèque: https://github.com/robfig/cron
Exemple ci-dessous:
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()
J'utilise le code suivant:
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")
}
C'est plus simple et ça me va.
Une réponse plus large à cette question pourrait envisager l’approche brique Lego souvent utilisée dans Occam et proposée à la communauté Java via JCSP . Il y a un très bon présentation de Peter Welch sur cette idée.
Cette approche plug-and-play se traduit directement en Go, car Go utilise les mêmes principes de base du processus de communication séquentielle qu'Occam.
Ainsi, lorsqu’il s’agit de concevoir des tâches répétitives, vous pouvez construire votre système en tant que réseau de flux de données constitué de composants simples (tels que des goroutines) qui échangent des événements (des messages ou des signaux) via des canaux.
Cette approche est compositionnelle: chaque groupe de petits composants peut se comporter lui-même comme un composant plus grand, à l'infini. Cela peut être très puissant car les systèmes concurrents complexes sont fabriqués à partir de briques faciles à comprendre.
Note de bas de page: dans la présentation de Welch, il utilise la syntaxe Occam pour les canaux, qui est ! et ? et ceux-ci correspondent directement à ch <- et à <- ch dans Go.
Si vous voulez l'arrêter à tout moment ticker
ticker := time.NewTicker(500 * time.Millisecond)
go func() {
for range ticker.C {
fmt.Println("Tick")
}
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
Si vous ne voulez pas l'arrêter cocher :
tick := time.Tick(500 * time.Millisecond)
for range tick {
fmt.Println("Tick")
}