Мой сценарий:
- У меня есть производитель и потребитель. Обе являются горутинами и общаются через один канал.
- Производитель способен (теоретически) генерировать сообщение в любое время.
- Генерация сообщения требует некоторых вычислений.
- Сообщение в некоторой степени чувствительно ко времени (т. е. чем оно старше, тем менее актуально).
- Потребитель время от времени читает с канала. Для примера предположим, что потребитель использует
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 Playground: 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.
}
}
}
select
. Производитель на самом деле считывает данные с другого канала, вычисляет некоторую статистику «на лету» и передает эту статистику потребителю. Потребителю нужно отображать статистику только один раз в секунду или около того, поэтому ему нужно потреблять только один раз в секунду. Но, возможно, это слишком запутанно, как вы говорите. - person Denilson Sá Maia   schedule 12.06.2019