web-dev-qa-db-fra.com

Y at-il un moyen de faire des tâches répétitives à intervalles dans Golang?

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)
}
133
Steve Brisk

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).

207
Paul Hankin

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")
}

Terrain de je

22
Volker

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")
    }
}

Terrain de je

20
Alekc

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()
16
Browny Lin

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.

3
Gustavo Emmel

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.

3
Rick-777

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")
}
0
John Balvin Arias