如何计算尽可能晚在通道上发送的消息?

时间:2019-06-12 10:12:26

标签: go nonblocking channel

我的情况:

  • 我有一个生产者和一个消费者。两者都是goroutine,它们通过一个通道进行通信。
  • 生产者能够(理论上)随时生成消息。
  • 生成消息需要一些计算。
  • 该消息在某种程度上是时间敏感的(即消息越旧,相关性越低)。
  • 消费者偶尔从该频道阅读。就本例而言,假设使用者每隔几秒钟使用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.
        }
    }
}

1 个答案:

答案 0 :(得分:0)

This answer(针对Go non-blocking channel send, test-for-failure before attempting to send?)建议使用第二个通道将信号从消费者发送到生产者:

  1. 消费者希望收到一条消息(例如,在收到timer.Ticker的滴答声之后)。
  2. 消费者通过侧面通道将信号发送到生产者goroutine。 (因此,对于此副渠道,生产者/消费者角色是相反的。)
  3. 制作人从副频道接收信号。
  4. 生产者开始计算真实消息。
  5. 制作人通过主渠道发送消息。
  6. 消费者收到消息。
相关问题