当生产者比消费者快得多时,为什么Disruptor会保存大量数据?

时间:2019-04-28 19:47:13

标签: disruptor-pattern

我正在学习Disruptor并遇到问题。当我有一个很大的环形缓冲区(例如1024)时,我的生产者比我的消费者快得多。直到我的应用程序结束,环形缓冲区将保存大量数据,但不会发布事件。这意味着我的应用程序将丢失很多数据(我的应用程序不是守护程序)。

我试图放慢生产者的速度,它有效。但是我不能在我的应用程序中使用这种方式,它将极大地降低我的应用程序的性能。

val ringBufferSize = 1024
val disruptor = new Disruptor[util.Map[String, Object]](new MessageEventFactory, ringBufferSize, new MessageThreadFactory, ProducerType.MULTI, new BlockingWaitStrategy)

      disruptor.handleEventsWith(new MessageEventHandler(batchSize, this))
      disruptor.setDefaultExceptionHandler(new MessageExceptionHandler)
      val ringBuffer = disruptor.start
      val producer = new MessageEventProducer(ringBuffer)
 part.foreach { row =>
//        Thread.sleep(2000)
        accm.add(1)
        producer.onData(row)

//        flush(row)
      }

我想找到一种方法来由我自己控制干扰器的批量大小,是否有任何方法可以在应用程序结束时消耗剩余的数据保留权?

1 个答案:

答案 0 :(得分:1)

如果您让应用程序突然终止,那么您的使用者当然也会突然终止。无需放慢生产者的速度,您只需要阻止应用程序退出,直到所有使用者(即事件处理程序)完成未完成的事件为止。

通常的方法是在主线程上调用Disruptor.shutdown(),从而阻止应用程序退出,直到Disruptor.shutdown()返回为止。

在上面的代码片段中,您将在part.foreach语句之后退出例程之前添加该命令,直到该例程正常返回为止,都将阻塞该命令。这样可以确保正确处理所有事件以完成操作。

Disruptor主要擅长于缓冲(平滑)来自单个(极快)或多个(仍非常快)生产者线程的数据突发,以将数据馈送到以可预测方式执行的使用者,从而消除了尽可能多的延迟和开销归因于锁争用。您可能会发现,如果生产者实际上比消费者快得多,则从lambda内简单地调用消费者代码可能会产生更好或相似的结果,除非您使用批处理或设置Disruptor等高级技术来运行多个实例。并行线程中的同一使用者,但这需要修改事件处理程序的实现(请参见the Disruptor FAQ)。

在您的示例中,您似乎想要完成的一切只是将一组已经可用的数据(您的“ part”集合)馈送到单个事件处理程序(MessageEventHandler)中。在这种用例中,您最好说一些类似parts.stream()。parallel()。foreach(... messageEventHanler.onEvent(event)...)