Используйте 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 .