30

由于 RingBuffer 预先分配给定类型的对象,如何使用单个环形缓冲区来处理各种不同类型的消息?

您不能创建新的对象实例来插入到 ringBuffer 中,这会破坏预先分配的目的。

因此,您可以在异步消息传递模式中有 3 条消息:

  1. 新订单请求
  2. 新订单已创建
  3. 新订单被拒绝

所以我的问题是你打算如何将 Disruptor 模式用于现实世界的消息系统?

谢谢

链接: http ://code.google.com/p/disruptor-net/wiki/CodeExamples

http://code.google.com/p/disruptor-net

http://code.google.com/p/disruptor

4

3 回答 3

33

一种方法(我们最常见的模式)是以编组形式存储消息,即作为字节数组。对于传入的请求,例如修复消息、二进制消息,被快速拉出网络并放置在环形缓冲区中。不同类型消息的解组和分派由该环形缓冲区上的 EventProcessors(消费者)处理。对于出站请求,消息被序列化为预先分配的字节数组,形成环形缓冲区中的条目。

如果您使用一些固定大小的字节数组作为预分配条目,则需要一些额外的逻辑来处理较大消息的溢出。即选择一个合理的默认大小,如果超过,分配一个更大的临时数组。然后在条目被重用或使用(取决于您的用例)恢复到原始预分配字节数组时丢弃它。

如果您对不同的消息类型有不同的使用者,您可以通过知道携带类型信息的字节数组的偏移量或通过在条目上传递鉴别器值来快速确定您的使用者是否对特定消息感兴趣。

此外,也没有禁止创建对象实例和传递引用的规则(我们也在几个地方这样做)。您确实失去了对象预分配的好处,但是破坏者的设计目标之一是允许用户选择最合适的存储形式。

于 2011-08-04T09:40:53.453 回答
6

有一个名为 Javolution (http://javolution.org/) 的库,可让您将对象定义为具有固定长度字段(如 string[40] 等)的结构,这些字段在内部依赖字节缓冲区而不是可变大小的对象......这允许使用固定大小的对象初始化令牌环,因此(希望)允许缓存更有效地工作的连续内存块。

我们使用它来传递事件/消息,并为我们的业务逻辑使用标准字符串等。

于 2012-04-04T19:49:25.500 回答
0

回到对象池。

以下是一个假设。

如果您将有 3 种类型的消息(A、B、C),您可以制作 3 个预先分配的数组。这将创建 3 个内存区域 A、B、C。

并不是只有一个缓存线,有很多而且它们不必是连续的。一些缓存行将引用区域 A、其他 B 和其他 C 中的某些内容。

所以环形缓冲区条目可以有 1 个对 A & B & C 的共同祖先或接口的引用。

问题是在池中选择实例;最简单的是具有与环形缓冲区长度相同的数组长度。这意味着大量浪费的池对象,因为在任何条目中只使用了 3 个中的一个,例如:环形缓冲区条目 1234 可能正在使用消息 B[1234] 但 A[1234] 和 C[1234] 未使用且不可用由任何人。

您还可以创建一个内联所有 3 个 A+B+C 实例的超级条目,并用一些字节或枚举指示类型。就像在内存大小上一样浪费,但由于条目的肥胖,看起来有点糟糕。例如,仅处理 C 消息的阅读器将具有较少的缓存局部性。

我希望我对这个假设没有太大的错误。

于 2018-03-17T01:04:28.387 回答