Java 如何使用具有多种消息类型的中断器

Java 如何使用具有多种消息类型的中断器,java,multithreading,performance,messaging,disruptor-pattern,Java,Multithreading,Performance,Messaging,Disruptor Pattern,我的系统有两种不同类型的消息-类型A和B。每条消息都有不同的结构-类型A包含一个int成员,类型B包含一个double成员。我的系统需要将这两种类型的消息传递给许多业务逻辑线程。减少延迟非常重要,因此我正在研究使用中断器以机械方式将消息从主线程传递到业务逻辑线程 我的问题是,中断器只接受环形缓冲区中的一种类型的对象。这是有意义的,因为中断器预先分配了环形缓冲区中的对象。然而,这也使得通过中断器向业务逻辑线程传递两种不同类型的消息变得困难。据我所知,我有四个选择: 将中断器配置为使用包含固定大小字

我的系统有两种不同类型的消息-类型A和B。每条消息都有不同的结构-类型A包含一个int成员,类型B包含一个double成员。我的系统需要将这两种类型的消息传递给许多业务逻辑线程。减少延迟非常重要,因此我正在研究使用中断器以机械方式将消息从主线程传递到业务逻辑线程

我的问题是,中断器只接受环形缓冲区中的一种类型的对象。这是有意义的,因为中断器预先分配了环形缓冲区中的对象。然而,这也使得通过中断器向业务逻辑线程传递两种不同类型的消息变得困难。据我所知,我有四个选择:

  • 将中断器配置为使用包含固定大小字节数组的对象(根据建议)。在这种情况下,主线程必须在将消息发布到中断器之前将消息编码到字节数组中,并且每个业务逻辑线程必须在收到消息后将字节数组解码回对象中。这种设置的缺点是业务逻辑线程没有真正共享来自中断器的内存,而是从中断器提供的字节数组创建新对象(从而创建垃圾)。这种设置的好处是,所有业务逻辑线程都可以从同一个中断器读取多种不同类型的消息

  • 将中断器配置为使用单一类型的对象,但创建多个中断器,每个对象类型一个。在上述情况下,将有两个独立的中断器-一个用于类型A的对象,另一个用于类型B的对象。此设置的好处是主线程不必将对象编码为字节数组,无业务逻辑线程可以共享中断器中使用的相同对象(不创建垃圾)。这种设置的缺点是,每个业务逻辑线程都必须订阅来自多个破坏者的消息

  • 将中断器配置为使用包含消息a和消息B的所有字段的单一类型的“super”对象。这非常不符合OO风格,但允许在选项1和选项2之间进行折衷

  • 将中断器配置为使用对象引用。但是,在这种情况下,我失去了对象预分配和内存排序的性能优势

  • 对于这种情况,你有什么建议?我觉得选项2是最干净的解决方案,但我不知道消费者是否或如何从技术上订阅来自多个破坏者的消息。如果有人能为如何实施方案2提供一个例子,我们将不胜感激

    将中断器配置为使用包含固定大小字节数组的对象 (根据如何使用干扰器(干扰器模式)来构建 真实世界的信息系统?)。在这种情况下,主线程必须对 将消息发布到中断器和每个 所有业务逻辑线程必须将字节数组解码回对象 收到后。这种设置的缺点是业务逻辑线程 他们并没有真正分享来自破坏者的记忆——相反,他们是 从字节数组创建新对象(从而创建垃圾) 由破坏者提供。这种设置的好处是所有业务 逻辑线程可以从同一个线程读取多种不同类型的消息 破坏者

    这是我的首选方法,但我对我们的 用例,几乎每个我们使用过破坏者的地方 接收或发送到某种I/O设备,因此 基本货币是字节数组。您可以绕过对象创建 通过使用飞锤方法进行编组。看一个例子 为此,我在一个示例中使用了Javolution的Struct和Union类 我出席了Devxx()。如果你 可以在从OneEvent返回之前完全处理对象 从事件处理程序调用,则此方法效果良好。如果 事件需要超出这一点,然后你需要做一些排序 数据的副本,例如,将其反序列化为对象

    将中断器配置为使用单一类型的对象,但创建多个 干扰器,每种对象类型一个。在上述情况下,将有 两个独立的干扰器-一个用于A型对象,另一个用于对象 B型。这种设置的优点是,主线程不必 将对象编码为字节数组,无业务逻辑线程可以 共享中断器中使用的相同对象(不创建垃圾)。这个 这种设置的缺点是,每个业务逻辑线程都会有 订阅来自多个破坏者的消息

    如果没有尝试这种方法,您可能需要一个定制的EventProcessor 可以从多个环形缓冲区轮询的

    将中断器配置为使用单一类型的“超级”对象,该对象包含 消息A和消息B的所有字段。这非常违反OO风格,但是 考虑选项1和选项2之间的折衷。 将中断器配置为使用对象引用。然而,在这种情况下,我 失去对象预分配和内存排序的性能优势

    我们已经在一些案例中这样做了,其中一些案例缺乏 预分配是可以容忍的。没问题。如果你路过 然后,您需要确保在创建对象后将其清空 在消费者方面完成了。我们发现使用双 “超级”对象的分派模式公平地保持了实现 清洁的这样做的一个缺点是,它会让你的时间稍微长一点 GC使用对象的直数组作为 T
    public enum MyEventEnum {
    EVENT_TIMER,
    EVENT_MARKETDATA;
    }
    
    public class RingBufferEventHolder {    
     private MyEventEnum;   
     private EventBase array[];
    
     public RingBufferEventHolder() {
        array=new EventBase[MyEventEnum.values().length]; 
     }
    
     // TODO: null the rest
     public void setEvent(EventBase event) {
        type=event.getType();
        switch( event.getType() ) {
            case EVENT_TIMER:
                array[MyEventEnum.EVENT_TIMER.ordinal()]=event;
                break;
            case EVENT_MARKETDATA:
                array[MyEventEnum.EVENT_MARKETDATA.ordinal()]=event;
                break;
            default:
                throw new RuntimeException("Unknown event type " + event );
        }
    }
    
       EventBase newEvent=new EventMarketData(....);
       // prepare
       long nextSequence = ringBuffer.next(); 
       RingBufferEventHolder holder = ringBuffer.get(nextSequence);
       holder.setEvent(newEvent);
       // make the event available to EventProcessors 
       ringBuffer.publish(nextSequence);
    
    public enum ExchangeEventType{
        PLACE_ORDER,   // -> OrderEvent
        CANCEL_ORDER,  // -> OrderEvent
        MARKET_FEED,   // -> MarketEvent
        MARKET_UPDATE, // -> MarketEvent
        ADD_USER,      // -> AccountEvent
        SUSPEND_USER,  // -> AccountEvent
        RESUME_USER    // -> AccountEvent
    }    
    
    public ExchangeEvent{
      private EventType type;
      private EventResultCode resultCode;
      private long timestamp;
    
      // event type objects
      private OrderEvent orderEvent;
      private MarketEvent marketEvent;
      private AccountEvent accountEvent;
    }