`

LMAX的Disruptor如何工作?(stackoverflow的回答)

 
阅读更多

原文地址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):

首先我们来理解一下它提供的编程模型。
它有一个或多个作者和读者。有一排从旧到新的条目(从左到右)。作者可以在右侧新增条目。每个读者按从左到右的顺序读取条目。读者显然不能跳过作者先读取。
条目不能被删除。我用“读者”代替“消费者”来避免让人以为条目会被消费掉。不过我们知道最后一个读者左边的条目是没有用处的。
通常读者可以并发地独立地读取条目。但是我们可以声明读者之间的依赖关系。读者间可以有任意非环形依赖。如果读者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,甚至是内存障(比如如果只有一个作者的话就使用不变的序列变量)。
写给开发者:不同注解的读者应该写到条目中不同的字段,从而避免写冲突。(事实上他们应该写在不同的缓存行中。)一个特定注解的读者不应该去碰无依赖的读者可能读到的任何东西。

 

转:http://www.cnblogs.com/adaikiss/archive/2012/02/15/2352545.html

分享到:
评论

相关推荐

    LMAX disruptor jar包+Demo+Api+src源码 disruptor-3.0.1.jar

    LMAX Disruptor 最新版本 源码+API+驱动包

    LMAX-Disruptor框架jar包

    Disruptor框架是由LMAX公司开发的一款高效的无锁内存队列。使用无锁的方式实现了一个环形队列。据官方描述,其性能要比BlockingQueue至少高一个数量级。根据GitHub上的最新版本源码打出的包,希望对大家有帮助。

    LMAX Disruptor的Go语言端口。-Golang开发

    Disruptor概述这是LMAX Disruptor进入Go编程语言的端口。 它保留了Disruptor的本质和精神,并使用了许多相同的抽象和概念,但并没有保持相同的Disruptor概述。这是LMAX Disruptor移植到Go编程语言中的移植。 它保留...

    LMAX.Disruptor,一个无锁高并发框架,中文文档

    LMAX是一种新型零售金融交 易平台,它能够以很低的延迟产生大量交易。这个系统是建立在JVM平台上,其核心是一个业务逻辑处理 器,它能够在一个线程里每秒处理6百万订单。业务逻辑处理器完全是运行在内存中,使用事件...

    disruptor-3.3.8.jar

    Error: java.lang.NoSuchMethodError: com.lmax.disruptor.dsl.Disruptor.<init>(Lcom/lmax/disruptor/EventFactory;ILjava/util/concurrent/ThreadFactory;Lcom/lmax/disruptor/dsl/ProducerType;Lcom/lmax/...

    disrustor:LMAX Disruptor的端口连接到Rust

    :warning: 免责声明:此板条箱有一个已知的安全漏洞,请参阅防锈剂该项目是到Rust的端口。特征 单一生产者 批量消费者 阻塞等待策略 旋转等待策略 多制片人 工人池 DSL 文献资料基准测试从生产者向消费者发送i32大小...

    rxmax:LMAX Disruptor使Rx Java最大化

    最大值 LMAX Disruptor使Rx Java最大化

    dispatcher:带有嵌入式 LMAX Disruptor 的快速事件路由器

    Dispatcher 是一个以 LMAX Disruptor 为核心的事件处理器。 使用批量写入,可以轻松获得超过每秒 100 万个事件的速率,在 MacBook Pro 上的上限仅为每秒 2000 万个事件(每个事件约 50ns)。 发出单个事件的性能仍然...

    disruptor-example:使用LMAX Disruptor环形缓冲区的示例

    LMAX Disruptor环形缓冲区示例 使用LMAX破坏者框架的示例: 受此博客文章的启发: 这是“钻石配置”的极其简化的版本,如以下内容所述: 在此实现中,日志记录和复制步骤同时发生,并且都必须成功才能执行发布...

    phaser:LMAX Disruptor 的 Clojure DSL

    移相器 LMAX Disruptor 的 Clojure DSL安装将以下依赖项添加到您的project.clj文件中: ; ; Stable[userevents/phaser " 1.1.5 " ]; ; or for the brave, use the cutting edge[userevents/phaser " 1.1.6-SNAPSHOT ...

    Disruptor-cpp:LMAX Disruptor到C ++的端口

    Disruptor-cpp 总览 Disruptor-cpp是功能齐全的C ++端口。 实现java Disruptor v3.3.7中可用的所有功能。 建造 编译器 Clang 3.8或更高版本 GCC 5.0或更高版本 Microsoft Visual C ++ 2015或更高版本 Linux 必须在...

    超高效的交易所撮合引擎,采用伦敦外汇交易所LMAX开源的Disruptor框架,分布式内存存取,以及原子性操作

    match-trade超高效的交易所撮合引擎,采用伦敦外汇交易所LMAX开源的Disruptor框架,分布式内存存取,以及原子性操作。使用数据流的方式进行计算撮合序列,才用价格水平独立撮合逻辑,实现高效大数据撮合

    disrupted-reactor:Java异步。 IO(基于选择器)+ LMAX Disruptor

    IO(基于选择器)+ LMAX Disruptor 需要Java 1.8。 实施的想法: select()的专用线程-React堆模式,通过特殊的WaitStrategy实现为一个中断实例。 N个线程(即处理器)处理IO事件。 一个NIO通道的处理始终在一个...

    LMAX Disruptor:高性能线程间消息传递库-开源

    LMAX旨在成为世界上最快的交易平台。 显然,为了实现这一目标,我们需要做一些特殊的事情,以通过我们的Java平台实现极低的延迟和高吞吐量。 性能测试表明,使用队列在系统各阶段之间传递数据会引入延迟,因此我们...

    串行io disruptor

    High performance alternative to bounded queues for exchanging data between concurrent threads

    Disruptor-net:LMAX Disruptor到.NET的端口

    Disruptor是一个高性能的线程间消息传递框架。 该项目是的.NET端口。 可以将Disruptor简洁地定义为具有可配置使用者序列的循环队列。 主要功能是: 初始设置后,内存分配为零(事件已预先分配)。 基于推送的消费...

    disruptor-3.3.0-API文档-中文版.zip

    标签:disruptor、lmax、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用...

    disruptor-3.3.0-API文档-中英对照版.zip

    标签:disruptor、lmax、jar包、java、API文档、中英对照版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,...

    Disruptor报错FatalExceptionHandler的解决办法,看网上这种解决办法挺少,整理了一下

    Disruptor报错FatalExceptionHandler的解决办法,看网上这种解决办法挺少,整理了一下,分析了一下Dsiruptor的源码,并给出了解决方案

    Disruptor 一种可替代有界队列完成并发线程间数据交换高性能解决方案.docx

    本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注。Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调生产者与消费者,从而避免使用锁和CAS,...

Global site tag (gtag.js) - Google Analytics