Как я могу вычислить сообщение для отправки на канал как можно позже? - PullRequest
0 голосов
/ 12 июня 2019

Мой сценарий:

  • У меня есть производитель и потребитель.Оба являются goroutines, и они общаются через один канал.
  • Производитель способен (теоретически) генерировать сообщение в любое время.
  • Генерация сообщения требует некоторых вычислений.
  • Сообщение несколько чувствительно ко времени (т. Е. Чем оно старше, тем оно менее актуально).
  • Пользователь время от времени читает с канала.В качестве примера, скажем, потребитель использует time.Ticker для чтения сообщения раз в пару секунд.
  • Потребитель предпочел бы «свежие» сообщения (т.е. сообщения, которые были сгенерированы как можно раньше).).

Итак, вопрос в следующем: Как производитель может сгенерировать сообщение как можно позже?


Пример кода, который показывает общиеидея:

func producer() {
    for {
        select {
        ...
        case pipe <- generateMsg():
            // I'd like to call generateMsg as late as possible,
            // i.e. calculate the timestamp when I know
            // that writing to the channel will not block.
        }
    }
}

func consumer() {
    for {
        select {
        ...
        case <-timeTicker.C:
            // Reading from the consumer.
            msg <- pipe
            ...
        }
    }
}

Полный код (немного отличающийся от приведенного выше) доступен на игровой площадке Go: https://play.golang.org/p/y0oCf39AV6P


Одна из идей, которую у меня возникла, заключалась в проверке записи в канал.будет блокировать.Если он не заблокируется, я могу сгенерировать сообщение и затем отправить его.Однако…

  • Я не смог найти способа проверить, будет ли запись в канал заблокирована или нет.
  • В общем случае это плохая идея, потому что она вводитгоночные условия, если у нас несколько производителей.В этом конкретном случае у меня есть только один производитель.

Еще одна (плохая) идея:

func producer() {
    var msg Message
    for {
        // This is BAD. DON'T DO THIS!
        select {
        case pipe <- msg:
            // It may send the same message multiple times.
        default:
            msg = generateMsg()
            // It causes a busy-wait loop, high CPU usage
            // because it re-generates the message all the time.
        }
    }
}

1 Ответ

0 голосов
/ 12 июня 2019

Этот ответ (для Перейти к неблокируемой отправке канала, проверка на отказ перед попыткой отправки? ) предлагает использовать второй канал для отправки сигнала от потребителя производитель:

  1. Потребитель хочет получить сообщение (например, после получения отметки от timer.Ticker).
  2. Потребитель отправляет сигнал через боковой канал в программу-производитель. (Таким образом, для этого побочного канала роли производителя / потребителя меняются местами).
  3. Производитель получает сигнал от бокового канала.
  4. Производитель начинает вычислять реальное сообщение.
  5. Производитель отправляет сообщение через основной канал.
  6. Потребитель получает сообщение.
...