1

我有一个包含许多生产者和消费者的应用程序。

据我了解,RingBuffer 在 RingBuffer init 开始时创建对象,然后在 Ring 中发布时复制对象并在 EventHandler 中从中获取它们。

我的应用程序 LogHandler 在列表中缓冲接收到的事件,以便在列表达到一定大小后进一步以批处理模式发送。因此 EventHandler#onEvent 将接收到的对象放入列表中,一旦达到大小,它就会在 RMI 中将其发送到服务器并清除它。

我的问题是,我是否需要在放入列表之前克隆对象,据我所知,一旦使用它们就可以重复使用?

我是否需要同步对 EventHandler#onEvent 中列表的访问?

4

2 回答 2

2

是的 - 你的理解是正确的。您将值复制进出环形缓冲区插槽。

我建议是的,当您从环形缓冲区中提取值并将其复制到事件处理程序列表中时,您可以克隆这些值;否则插槽可以重复使用。

只要列表是事件处理程序的私有成员变量并且每个线程只有一个事件处理程序实例,您就不需要同步对列表的访问。如果您有多个事件处理程序添加到同一个(例如静态)列表实例,那么您将需要同步。


澄清:

请务必阅读下面 OzgurH 评论中的背景。如果您坚持在中断器上使用 endOfBatch 标志并使用它来决定批次的大小,则不必将对象复制到列表之外。如果您使用自己的累积策略(例如大小 - 根据问题),那么您应该克隆对象,因为插槽可以在您有机会发送之前重复使用。

另外值得注意的是,如果您需要在列表实例上进行同步,那么您已经错过了使用破坏者的大好机会,并且无论如何都会破坏您的性能。

于 2013-08-18T22:32:09.587 回答
2

可以在 Disruptor 的 RingBuffer 中使用槽(包括包含 a 的槽List)而无需克隆/复制值。这对您来说可能是一个更可取的解决方案,具体取决于您是否担心垃圾创建,以及您是否真的需要关注对放置在 RingBuffer 中的对象的并发更新。如果放置在插槽列表中的所有对象都是不可变的,或者如果它们一次只被一个线程更新/读取(Disruptor 经常用来强制执行的前提条件),那么克隆它们不会有任何收获因为他们已经不受数据竞争的影响。

关于批处理,请注意 Disruptor 框架本身提供了一种机制,用于在 EventHandler 线程中批量从 RingBuffer 中获取项目。这种方法是完全线程安全且无锁的,并且可以通过使您的内存访问模式对 CPU 更可预测而产生更好的性能。

于 2013-08-19T17:37:31.107 回答