0

https://martinfowler.com/articles/lmax.html中所述,我需要先使用 Unmarchaler 处理我的 RingBuffer 事件,然后再使用业务逻辑处理器。假设它的配置如下(https://lmax-exchange.github.io/disruptor/docs/com/lmax/disruptor/dsl/Disruptor.html

  Disruptor<MyEvent> disruptor = new Disruptor<MyEvent>(MyEvent.FACTORY, 32, Executors.newCachedThreadPool());
  EventHandler<MyEvent> handler1 = new EventHandler<MyEvent>() { ... };
  EventHandler<MyEvent> handler2 = new EventHandler<MyEvent>() { ... };
 disruptor.handleEventsWith(handler1);
 disruptor.after(handler1).handleEventsWith(handler2);

想法是handler1是unmarchaler,handler2消耗handler1处理的东西。

问题:我如何才能准确地编码“unmarchaling 并放回破坏者”部分?我找到了这个https://groups.google.com/forum/#!topic/lmax-disruptor/q6h5HBEBRUk解释,但我不太明白。假设事件到达handler1的回调

void onEvent(T event, long sequence, boolean endOfBatch) 

(javadoc:https ://lmax-exchange.github.io/disruptor/docs/com/lmax/disruptor/EventHandler.html )

从事件中取消编组一些数据。现在我需要将未编组的数据附加到将处理未编组对象的handler2的事件中。

“更新”事件需要做什么?修改“事件”对象是否足够?

4

1 回答 1

2

这样做的影响实际上取决于您的特定场景,并且与往常一样,如果您追求低延迟,您应该尝试两者并进行基准测试。

最直接的方法是更新“事件”对象,但是根据您的特定方法,这可能会错过破坏者的许多单一写入者的好处。我将解释并提供一些选项。

例如,假设您有 handler1 和 handler2,handler1 在 thread1 中运行,handler2 在 thread2 中运行。初始事件发布者位于 thread0 上。

  • Thread0 将一个条目写入到插槽 1 的缓冲区中
  • Thread1 读取槽 1 中的条目并写入槽 1
  • Thread0 在插槽 2 处将条目写入缓冲区
  • Thread2 从插槽 1 读取并写入输出
  • Thread1 读取插槽 2 中的条目并写入插槽 2
  • Thread2 从插槽 2 读取并写入输出

如果您考虑物理内存布局,slot1 和 slot2 在内存中希望彼此相邻。例如,它们可能是字节数组的某个子集。如您所见,您正在从不同的线程(可能是不同的 cpu 内核)交替读取和写入非常相邻的内存块,这可能导致错误的共享/缓存线弹跳。最重要的是,您通过内存的读取和写入不太可能是线性的,因此您将错过 CPU 缓存的一些好处。

其他一些可能更好的选项:

  • 有单独的环形缓冲区,其中第一个环形缓冲区是原始数据,第二个环形缓冲区是未编组的事件。通过这种方式,数据在内存中被充分分离以避免这些成本。然而,这将产生带宽影响。

  • 让解组器和工作直接在同一个处理程序中完成。根据解组器和处理程序中的工作量,这可能是可行的。

于 2017-01-19T00:56:59.230 回答