LMAX的Disruptor怎么工作?(stackoverflow)

评分 0, 满分 5 星(397 次阅读)
Loading...
添加评论

原文地址http://stackoverflow.com/questions/6559308/how-does-lmaxs-disruptor-pattern-work

第一个答复(answered Jul 3 ""11 at 8:03 Michael Barker):

Disruptor最简单的描述就是:它是线程间通信最高效的体式格式。它可以用来调换队列,同时有很多SEDA和Actors模式的特点。
和队列斗劲:
Disruptor可以向其他线程发送消息,并在须要的时辰唤醒其他线程(和BlockingQueue类似)。不过,他们之间有三个首要的差别。
1. 应用者经由过程持续Entry类并供给一个做预分派之用的工厂来定义消息如何存储。如许可以反复哄骗(复制)内存,或者所实现的Entry可以持有其他对象的引用。
2. 把消息放入Disruptor须要2个步调,起首在ring buffer中申明一个接口,这个接口供给应用者一个可以存放正确数据的Entry。然后必须提交这个entry,要想像上文提到的那样灵活应用内存,这两个步调是必须的。提交操纵使得花费者线程可以读作废息。
3. ring buffer中被花费的消息应当由花费者来追踪。不让ring buffer来追踪消息可以削减写冲突的呈现,因为每个线程都本身保护计数器。
与Actors斗劲
Actor模型是最接近Disruptor的法度模型,尤其是应用BatchConsumer/BatchHandler类。这些类隐蔽了所有对峙已花费的序列号的错杂实现的并且在首要工作产生的时辰会供给一些简单的回调办法。不过有两个小小的差别。
1. Disruptor应用一个线程对应一个花费者的模型,而Actors应用多对多的模型,比如你可以拥有尽可能多的actor,它们会分布在必然命量的线程上(一般一个核心一个actor)。
2. BatchHandler接口供给了一个额外的(并且是很首要的)回调办法onEndOfBatch().它容许耗时操纵,比如将I/O操纵放到批处理惩罚中一路履行以进步吞吐量。应用其他Actor框架也可以作批处理惩罚,然则它们几乎都没有供给批处理惩罚履行停止的回调办法,你只能应用超时来断定批处理惩罚是否停止,从而导致差的延时。
和SEDA斗劲
LMAX设计Disruptor模式是为了调换SEDA。
1. 和SEDA比拟,disruptor首要的改进就是可以并行工作。Disruptor支撑组播消息来实现这个功能,雷同的消息(以一致的次序)被发送给多个花费者。如许可以避免在管道中交叉层。
2. 花费者可以依附其他花费者的处理惩罚成果,经由过程把一个队列化的层放在它们之间。一个花费者可以简单地看到本身所依附的花费者的序列号。如许可以避免在管道中归并层。
和内存障斗劲
可以把dispruptor懂得为一个布局化的,有序的内存障。此中临盆者障碍相当于写障碍,花费者障相当于读障碍。

 

第二个答复(answered Jul 16 ""11 at 5:48 irreputable):

起首我们来懂得一下它供给的编程模型。
它有一个或多个作者和读者。有一排从旧到新的条目(从左到右)。作者可以在右侧新增条目。每个读者按从左到右的次序读取条目。读者显然不克不及跳过作者先读取。
条目不克不及被删除。我用“读者”庖代“花费者”来避免让人认为条目会被花费掉。不过我们知道最后一个读者左边的条目是没有效处的。(www.pms.cc 文章来源)
凡是读者可以并发地自力地读取条目。然则我们可以声明读者之间的依附关系。读者间可以有随便率性非环形依附。若是读者B依附于读者A,读者B不克不及跳过读者A先读取。
读者A可以注解一个条目,而读者B依附于这个注解,所以就有了读者间的依附。例如,A在一个条目上做一些策画,然后将成果保存到条目中的a字段。然后A进步,之后B可以读取这个条目和条目中的a。若是读者C没有依附于A,那么C就不该该读取a。
这的确是一个有趣的编程模型。不管机能如何,单单这个模型就对应用很有益处。
当然了,LMAX的首要目标就是机能。Disruptor应用一个预分派的条目环。这个环足够大,然则有上限,从而不会超出容量。若是环满了,作者会一向守候,直到最慢的作者进步而腾出空间。
条目对象是预分派的并且会一向存在,以削减GC的消费。我们不会增长新的条目对象或是删除旧的,相反的,作者会恳求一个已存在的条目,填充它的字段,然后通知读者。这两个步调真的是很简单的原子操纵。

setNewEntry(EntryPopulator);
interface EntryPopulator{ void populate(Entry existingEntry); }

预分派的条目相当于adjacent memory cells中的adjacent entries分派(很像),并且因为读者是次序读取条目,所以哄骗CPU缓存很首要。
还有做了很多尽力来避免锁,CAS,甚至是内存障(比如若是只有一个作者的话就应用不变的序列变量)。
写给开辟者:不合注解的读者应当写到条目中不合的字段,从而避免写冲突。(事实上他们应当写在不合的缓存行中。)一个特定注解的读者不该该去碰无依附的读者可能读到的任何器材。MRMY(www.pms.cc 文章来源)

声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: LMAX的Disruptor怎么工作?(stackoverflow)
 
评分 4.4, 满分 5 星
Loading...