2017-01-18 5 views
0

Как объясняется в https://martinfowler.com/articles/lmax.html, мне сначала нужно обработать события RingBuffer с помощью Unmarchaler, а затем с помощью Business Logic Processor. Предположим, что он настроен как (https://lmax-exchange.github.io/disruptor/docs/com/lmax/disruptor/dsl/Disruptor.html)Передача данных между последовательными потребителями в LMAX Disruptor (от unmarchaler до бизнес-логики)?

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.

Quesion: Как я могу точно скопировать часть «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)

ООН-marchals некоторые из данных событий. Теперь мне нужно добавить unmarchaled данные к событию для handler2, который будет иметь дело с unmarchaled объектом.

Что нужно сделать для события «обновления»? Изменяет ли объект «событие» достаточно?

ответ

1

Влияние этого действительно зависит от вашего конкретного сценария, и, как всегда, если вы после небольшой латентности, вы должны попробовать оба и бенчмарк.

Самый простой способ обновить объект «событие», однако в зависимости от вашего конкретного подхода это может пропустить много преимуществ одиночного писателя от разрушителя. Я объясню и предложим некоторые варианты.

Предположим, например, у вас есть handler1 и handler2, handler1 работает в thread1 и handler2 работает в thread2. Первоначальный издатель событий находится на thread0.

  • Thread0 записывает запись в буфер в слоте 1
  • Резьба1 считывает запись в слоте 1 и записывает в слот 1
  • Thread0 записывает запись в буфер в слоте 2
  • Резьба2 считывает из слот 1 и записывает на выход
  • Резьба1 считывает запись в слоте 2 и записывает в слот 2
  • Резьба2 считывает из слота 2 и записывает на выход

Если вы думаете о расположении физической памяти, слот1 и слот2 надеются рядом друг с другом в памяти. Например, они могут быть некоторым подмножеством массива байтов. Как вы можете видеть, вы читаете и записываете альтернативно из разных потоков (возможно, разных ядер процессора) в очень смежные куски памяти, что может привести к ложным линиям совместного доступа/кэша. Кроме того, ваши чтения и записи через память вряд ли будут линейными, поэтому вы пропустите некоторые преимущества кэшей CPU.

Некоторые другие варианты, которые могли бы быть лучше:

  • Есть отдельные ringbuffers, где первый ringbuffer является необработанные данные, а второй ringbuffer является unmarshalled событий. Таким образом, данные достаточно разделены в памяти, чтобы избежать этих затрат.Однако это будет иметь влияние полосы пропускания.

  • Имейте маршаллер и работу, выполненную непосредственно в одном и том же обработчике. В зависимости от объема работы вашего маркера и вашего обработчика это может быть жизнеспособным.