Есть ли способ, чтобы сделать повторяющиеся задачи с интервалами в Golang?



есть ли способ сделать повторяющиеся фоновые задачи в Go? Я думаю о чем-то вроде Timer.schedule(task, delay, period) в Java. Я знаю, что могу сделать это с goroutine и Time.sleep(), но я хотел бы что-то, что легко остановлены.



вот что я получил, но выглядит уродливо для меня. Есть ли более чистый / лучший способ?



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)
}
820   7  
go

7 ответов:

функции time.NewTicker создает канал, который отправляет периодическое сообщение, и предоставляет способ остановить его. Используйте его что-то вроде этого (непроверенный):

ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
    for {
       select {
        case <- ticker.C:
            // do stuff
        case <- quit:
            ticker.Stop()
            return
        }
    }
 }()

вы можете остановить работника, закрыв quit канал: close(quit).

Как насчет чего-то вроде

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

детская площадка

Если вы не заботитесь о смещении тика (в зависимости от того, сколько времени это заняло ранее при каждом выполнении), и вы не хотите использовать каналы, можно использовать функцию собственного диапазона.

т. е.

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

детская площадка

проверьте эту библиотеку:https://github.com/robfig/cron

пример, как показано ниже:

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

более широкий ответ на этот вопрос может рассмотреть подход Lego brick, часто используемый в Occam, и предлагаемый сообществу Java через JCSP. Там очень хорошо презентация Питера Уэлча на этой идее.

этот подход plug-and-play переводится непосредственно в Go, потому что Go использует те же принципы последовательного процесса связи, что и Occam.

поэтому, когда дело доходит до проектирования повторяющихся задач, вы можете построить свою систему как сеть потока данных простых компонентов (как goroutines), которые обмениваются событиями (т. е. сообщениями или сигналами) через каналы.

этот подход является композиционным: каждая группа малых компонентов может сама вести себя как более крупный компонент, до бесконечности. Это может быть очень мощным, потому что сложные параллельные системы сделаны из простых для понимания кирпичей.

сноска: в презентации Уэлча он использует синтаксис Occam для каналов, который ! и ? и они прямо соответствуют ch и в Go.

Если вы хотите, чтобы остановить его в любой момент бегущая строка

ticker := time.NewTicker(500 * time.Millisecond)
    go func() {
        for range ticker.C {
            fmt.Println("Tick")
        }
    }()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()

Если вы не хотите, чтобы остановить его ТИК:

 tick := time.Tick(500 * time.Millisecond)
for range tick {
        fmt.Println("Tick")
}

Я использую следующий код:

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

Это более простой и прекрасно работает для меня.

Comments

    Ничего не найдено.