Рассмотрим сервер, инициализированный ресурсом таймера / тикера, который будет запускать каждые тики t
(t
- 20 мс в моем примере). Каждый раз, когда сервер прослушивает что-то в сети (например, периодический сигнал от пиров), он должен сбросить таймер. С другой стороны, если таймер истекает без сброса (например, все его одноранговые узлы мертвы), он вызывает какое-то событие (в моем примере я просто печатаю время от запуска программы).
У меня проблемы с реализацией этого поведения с помощью time.Ticker
. Сброс таймера, кажется, работает (он не срабатывает в течение первых 50 мс), но тикер не активен (не тикает каждые 20 мс) после этого.
package main
import (
"fmt"
"time"
)
var wallclock time.Time
type server struct {
timeout *time.Ticker
stop chan bool
}
func (srv *server) start() {
for {
select {
case <-srv.timeout.C:
{
elapsed := time.Since(wallclock)
fmt.Println("timed out after ", elapsed, " elapsed from start ")
}
case <-srv.stop:
{
return
}
}
}
}
func main() {
wallclock = time.Now()
//make the server with a timer that will fire every 20ms
srv := server{
timeout: time.NewTicker(20 * time.Millisecond),
//channel to indicate the server to stop listening
stop: make(chan bool),
}
//start listening on a different thread
go srv.start()
for i := 0; i < 5; i++ {
//reset it every 10ms
time.Sleep(10 * time.Millisecond)
srv.timeout.Stop()
//as the reset frequency is higher,
//I'm not expecting this to fire within
//the first 50ms (5*10ms)
srv.timeout = time.NewTicker(20 * time.Millisecond)
}
//sleep for 110ms
//I'm expecting the timer to fire at least 5 times here
time.Sleep(110 * time.Millisecond)
//stop listening
srv.stop <- true
fmt.Println("Hi from tckr!")
}
Я ожидаю увидеть что-то вроде
timed out after ~70ms elapsed from start
timed out after ~90ms elapsed from start
timed out after ~110ms elapsed from start
timed out after ~130ms elapsed from start
timed out after ~150ms elapsed from start
Hi from tckr!
Пять раз, потому что я позволил основному потоку спать в течение 110 мс, а таймер 20 мс мог срабатывать пять раз за этот интервал.
Но я просто вижу Hi from tckr!
. srv.timeout = time.NewTicker(20 * time.Millisecond)
является правильным способом сброса Ticker
?
Если я не остановлю тикер в цикле for
(srv.timeout.Stop()
), тикер, кажется, продолжает тикать. Вот пример вывода после комментирования srv.timeout.Stop()
.
timed out after 20.6872ms elapsed from start
timed out after 41.4278ms elapsed from start
timed out after 61.8747ms elapsed from start
timed out after 72.7793ms elapsed from start
timed out after 94.1448ms elapsed from start
timed out after 112.5283ms elapsed from start
timed out after 134.0131ms elapsed from start
timed out after 152.5846ms elapsed from start
Hi from tckr!
Я не хочу, чтобы тикер срабатывал в течение первых 50 мс (т. Е. Я не хочу видеть первые две строки с 20,6872 мс и 41,4278 мс).