以惯用的方式创建带有额外标志的频道

Create channels with extra flags in an idiomatic way

TL;DR 我想要一个功能,其中一个通道有两个额外的字段,告诉生产者是否允许发送到通道,如果允许则告诉生产者消费者期望什么价值。虽然我知道如何使用共享内存来做到这一点,但我认为这种方法违背了 Go 的思想“不要通过共享内存进行通信;相反,通过通信共享内存。”

上下文:

我希望有一个运行(除了其他)三个 goroutines 的服务器 S:

  1. 只接收 UDP 数据包并将其发送到多路分解器的侦听器。
  2. 多路分解器获取网络数据包并根据一些数据将其发送到多个通道之一
  3. 侦听一个特定通道并处理在该通道上接收到的数据的处理任务。

为了检查网络上的一些设备是否还活着,处理任务会周期性地通过网络发送随机数,然后等待k秒。在那 k 秒内,我的协议的其他参与者收到随机数将发送一个包含(除了其他信息)随机数的回复。解复用器将从侦听器接收数据包,解析它们并将它们发送到 processing_channel。在 k 秒过去后,处理任务处理由多路分解器推送到 processing_channel 的消息。

我希望多路分解器不只是盲目地将它收到的任何响应(正确类型)发送到 processing_channel,而是检查处理任务当前是否正在等待任何消息,如果是的话它期望的 nonce 值。我做出这个设计决定是为了尽快丢弃不需要的数据包。

我的做法:

在其他语言中,我会有一个包含以下字段(伪代码)的 class:

class ActivatedChannel{
    boolean    flag_expecting_nonce;
    int        expected_nonce;
    LinkedList chan;
}

多路分解器随后会在收到正确类型的数据包后简单地获取 ActivatedChannel processing_channel 对象的锁,检查是否设置了标志并且随机数匹配,如果是,则将消息添加到 LinkedList chan!

问题:

这种方法利用了锁和共享内存,这与 Golang 的“不要通过共享内存进行通信;相反,通过通信共享内存”的口头禅不一致。因此,我想知道... :

  1. ...在 Go 依赖共享内存的意义上,我的方法是否“不好”。
  2. ...如何以更像 Go 的方式实现概述的结果。

是的,您描述的方法与 Golang 惯用的实现方式不一致。您正确地指出,在上述方法中,您是通过共享内存进行通信的。

为了以 Go 的惯用方式实现这一点,其中一种方法可能是您的 Demultiplexer “记住”所有期待随机数的 processing_channels 和随机数的相应类型。每当 processing_channels 准备好接收回复时,它会向 Demultiplexe 发送一个信号,表示它正在等待回复。

由于 Demultiplexer 是所有通信的中心,它可以维护 processing_channel 和它期望的相应随机数之间的映射。它还可以维护所有 processing_channels 等待回复的“注册表”。

在这种方法中,我们是 Sharing memory by communicating

要传达 processing_channel 正在等待回复,可以使用以下 struct

type ChannelState struct {
    ChannelId        string // unique identifier for processing channel
    IsExpectingNonce bool
    ExpectedNonce    int
}

在这种方法中,没有使用锁。