Вы не можете прервать time.Sleep()
.
Вместо этого, если вам нужно слушать другие «события» во время ожидания чего-либо, вы должны использовать каналы и операторы select
. select
аналогичен switch
, но в случаях все относится к операциям связи.
Хорошо, что select
состоит в том, что вы можете перечислить несколько случаев, все ссылающиеся на комм. ops (например, канал получает или отправляет), и любая операция может продолжаться (, выбирая один случайным образом, если несколько может продолжаться ). Если никто не может продолжить, он будет блокировать (ждать), пока один из комм. операции могут продолжаться (если нет default
).
Событие «тайм-аут» может быть реализовано с использованием time.After()
или серии «непрерывных» событий тайм-аута (тики или тактовые импульсы) с использованием time.Ticker
.
Вы должны изменить свой обработчик кнопки для отправки значения (состояния кнопки) на канал, чтобы получение от этого канала можно было добавить к select
внутри poll()
и обрабатывать «немедленно» (без ожидания тайм-аут или следующее событие тика).
См. Этот пример:
func poll(buttonCh <-chan bool) {
isDevice := false
read := func() {
if isDevice {
device1()
} else {
sensor1()
}
}
ticker := time.NewTicker(1 * time.Second)
defer func() { ticker.Stop() }()
for {
select {
case isDevice = <-buttonCh:
case <-ticker.C:
read()
}
}
}
func device1() { log.Println("reading device1") }
func sensor1() { log.Println("reading sensor1") }
Тестирование:
buttonCh := make(chan bool)
// simulate a click after 2.5 seconds:
go func() {
time.Sleep(2500 * time.Millisecond)
buttonCh <- true
}()
go poll(buttonCh)
time.Sleep(5500 * time.Millisecond)
Вывод (попробуйте на Go Playground ):
2009/11/10 23:00:01 reading sensor1
2009/11/10 23:00:02 reading sensor1
2009/11/10 23:00:03 reading device1
2009/11/10 23:00:04 reading device1
2009/11/10 23:00:05 reading device1
Это решение позволяет легко добавлять любое количество источников событий, ничего не меняя. Например, если вы хотите добавить событие «завершение работы» и «чтение сейчас» к вышеупомянутому решению, это будет выглядеть так:
for {
select {
case isDevice = <-buttonCh:
case <-ticker.C:
read()
case <-readNowCh:
read()
case <-shutdownCh:
return
}
}
Где shutdownCh
- канал с любым типом элемента, и чтобы сообщить об отключении, вы делаете это, закрывая его:
var shutdownCh = make(chan struct{})
// Somewhere in your app:
close(shutdownCh)
Закрытие канала имеет то преимущество, что у вас может быть любое количество подпрограмм, «контролирующих» его, все получат отключение (это похоже на трансляцию). Прием из закрытого канала может быть продолжен немедленно, давая нулевое значение типа элемента канала.
Чтобы выполнить действие «немедленное чтение», вы должны отправить значение на readNowCh
.