Запускать несколько функций одновременно с интервалами в Go - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть список функций и их соответствующие интервалы.Я хочу запускать каждую функцию с определенным интервалом одновременно.

В JavaScript я написал что-то вроде:

maps.forEach(({fn, interval}) => {
    setInterval(fn, interval)
})

Как реализовать эту функцию в Golang?

1 Ответ

0 голосов
/ 18 сентября 2018

Используйте time.Ticker для периодического получения «событий», которые вы можете использовать для определения времени выполнения функции.Вы можете получить time.Ticker, позвонив по номеру time.NewTicker().Возвращенный тикер имеет канал, по которому периодически отправляются значения.

Используйте программу для непрерывного получения событий и вызова функции, например, с помощью цикла for range.

Давайте посмотрим на 2 функции:

func oneSec() {
    log.Println("oneSec")
}

func twoSec() {
    log.Println("twoSec")
}

Вот простой планировщик, который периодически вызывает данную функцию:

func schedule(f func(), interval time.Duration) *time.Ticker {
    ticker := time.NewTicker(interval)
    go func() {
        for range ticker.C {
            f()
        }
    }()
    return ticker
}

Пример использования:

func main() {
    t1 := schedule(oneSec, time.Second)
    t2 := schedule(twoSec, 2*time.Second)
    time.Sleep(5 * time.Second)
    t1.Stop()
    t2.Stop()
}

Пример вывода (попробуйте на Go Playground ):

2009/11/10 23:00:01 oneSec
2009/11/10 23:00:02 twoSec
2009/11/10 23:00:02 oneSec
2009/11/10 23:00:03 oneSec
2009/11/10 23:00:04 twoSec
2009/11/10 23:00:04 oneSec

Обратите внимание, что Ticker.Stop() не закрывает канал тикера, поэтому for range не завершится;Stop() останавливает только отправку значений по каналу тикера.

Если вы хотите завершить выполнение процедур, используемых для планирования вызовов функций, вы можете сделать это с дополнительным каналом.И тогда эти программы могут использовать оператор select, чтобы «отслеживать» канал тикера и этот канал done, и возвращаться при успешном получении от done.

Например:

func schedule(f func(), interval time.Duration, done <-chan bool) *time.Ticker {
    ticker := time.NewTicker(interval)
    go func() {
        for {
            select {
            case <-ticker.C:
                f()
            case <-done:
                return
            }
        }
    }()
    return ticker
}

И используя его:

func main() {
    done := make(chan bool)
    t1 := schedule(oneSec, time.Second, done)
    t2 := schedule(twoSec, 2*time.Second, done)
    time.Sleep(5 * time.Second)
    close(done)
    t1.Stop()
    t2.Stop()
}

Попробуйте это на Go Playground .

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

Последние слова:

Если у вас есть фрагмент пар «функция-интервал», просто используйтецикл для передачи каждой пары этой функции schedule().Примерно так:

type pair struct {
    f        func()
    interval time.Duration
}

pairs := []pair{
    {oneSec, time.Second},
    {twoSec, 2 * time.Second},
}

done := make(chan bool)
ts := make([]*time.Ticker, len(pairs))
for i, p := range pairs {
    ts[i] = schedule(p.f, p.interval, done)
}

time.Sleep(5 * time.Second)
close(done)

for _, t := range ts {
    t.Stop()
}

Попробуйте это на Go Playground .

...