我正在尝试理解破坏者模式。我观看了 InfoQ 视频并尝试阅读他们的论文。我知道涉及一个环形缓冲区,它被初始化为一个非常大的数组,以利用缓存局部性,消除新内存的分配。
听起来好像有一个或多个原子整数来跟踪位置。每个“事件”似乎都有一个唯一的 ID,并且通过查找其相对于环的大小的模数等来找到它在环中的位置。
不幸的是,我对它是如何工作的没有直观的感觉。我做过很多交易应用并研究过演员模型,查看了SEDA等。
在他们的演讲中,他们提到这种模式基本上就是路由器的工作方式;但是我也没有找到关于路由器如何工作的任何好的描述。
有一些好的指示可以提供更好的解释吗?
Google Code 项目确实参考技术论文关于环形缓冲区的实现,但是对于想要了解其工作原理的人来说,这有点枯燥、学术性和困难。然而,有一些博客文章已经开始以更易读的方式解释内部结构。有一个环形缓冲区的解释这是颠覆者模式的核心,消费者壁垒描述(与从干扰器读取相关的部分)和一些有关处理多个生产者的信息可用的。
对 Disruptor 最简单的描述是:它是一种以最有效的方式在线程之间发送消息的方法。它可以用作队列的替代品,但它也与 SEDA 和 Actor 共享许多功能。
与队列相比:
Disruptor 提供将消息传递到另一个线程的能力,并在需要时唤醒它(类似于 BlockingQueue)。然而,有 3 个明显的差异。
- Disruptor 的用户通过扩展 Entry 类并提供一个工厂来进行预分配来定义如何存储消息。这允许内存重用(复制),或者 Entry 可以包含对另一个对象的引用。
- 将消息放入 Disruptor 是一个两阶段的过程,首先在环形缓冲区中声明一个槽,为用户提供可以填充适当数据的条目。然后必须提交该条目,这种两阶段方法对于灵活使用上述内存是必要的。正是提交使消息对消费者线程可见。
- 消费者有责任跟踪已从环形缓冲区消费的消息。将这一责任从环形缓冲区本身移开有助于减少写入争用量,因为每个线程都维护自己的计数器。
与演员相比
Actor 模型比大多数其他编程模型更接近 Disruptor,特别是如果您使用提供的 BatchConsumer/BatchHandler 类。这些类隐藏了维护所使用的序列号的所有复杂性,并在重要事件发生时提供一组简单的回调。然而,存在一些细微的差异。
- Disruptor 使用 1 线程 - 1 消费者模型,其中 Actor 使用 N:M 模型,即您可以拥有任意数量的 Actor,并且它们将分布在固定数量的线程(通常每个核心 1 个)上。
- BatchHandler 接口提供了一个额外的(并且非常重要的)回调
onEndOfBatch()
。这允许缓慢的消费者,例如那些执行 I/O 将事件一起批处理以提高吞吐量的人。可以在其他 Actor 框架中进行批处理,但是由于几乎所有其他框架在批处理结束时都不提供回调,因此您需要使用超时来确定批处理的结束,从而导致延迟很差。
与SEDA相比
LMAX 构建了 Disruptor 模式来取代基于 SEDA 的方法。
- 它相对于 SEDA 的主要改进是并行工作的能力。为此,Disruptor 支持将相同的消息(以相同的顺序)多播给多个消费者。这避免了管道中对分叉阶段的需要。
- 我们还允许消费者等待其他消费者的结果,而不必在他们之间放置另一个排队阶段。消费者可以简单地查看它所依赖的消费者的序列号。这避免了管道中连接阶段的需要。
与内存屏障相比
另一种思考方式是将其视为结构化、有序的内存屏障。其中生产者屏障形成写屏障,而消费者屏障形成读屏障。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)