Голанг: Прерывание бесконечного опроса, имеющего время. Сон - PullRequest
0 голосов
/ 14 мая 2018

Я использую следующий простой механизм опроса:

    func poll() {

        for {
            if a {
                device1()
                time.Sleep(time.Second * 10)
            } else {
                sensor1()
                time.Sleep(time.Second * 10)
            }
        }
    }

Мне нужно опросить устройство1, только если «а» истинно, в противном случае опросите датчик1. Теперь здесь «а» будет установлен в «истина», нажав кнопку на пользовательском интерфейсе, что будет случайным действием.

Но из-за времени. Сон, вводится задержка при проверке состояния.

Есть ли способ немедленно остановить время. Спать, когда я получаю значение для "а"? Каковы возможные способы реализации таких прерываний при опросе в golang?

1 Ответ

0 голосов
/ 14 мая 2018

Вы не можете прервать 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.

...