如何从 Ring Buffer 读取?

原文地址:http://mechanitis.blogspot.com/2011/06/dissecting-disruptor-how-do-i-read-from.html​​ 作者是 Trisha Gee, LMAX 公司的一位女工程师。

这是理解 LMAX​ 开发的 Disruptor 模式​ 系列博客的下一篇。

上一篇博客​ 我们都明白了什么是 Ring Buffer 以及 它有多棒。遗憾的是,我还没有提到当你实际使用 Disruptor 时,怎样读写数据。

ConsumerBarrier 与消费者

这里我要稍微反过来介绍,因为总的来说这一段比较容易理解。假设一些魔法已经把数据填入 Ring Buffer 了,怎样从 Ring Buffer 读出这些数据?

(唔,我开始后悔使用 Paint/Gimp​ 了。尽管这是个购买绘图板的好借口,如果我继续写下去的话... UML 界的权威们大概也在诅咒我的名字了。)

消费者(Consumer)是一个想从 Ring Buffer 里拿出数据的线程,它可以访问 ConsumerBarrier 对象——这个对象由 RingBuffer 创建并且代表消费者与它互动。就像 Ring Buffer 显然需要序号才能找到下一个可用节点一样,消费者一样需要知道序号——每个消费者都需要找到下一个它要访问的序号。在上面的例子中,消费者处理完了 Ring Buffer 里序号 8 之前的所有数据,那么它期待访问的下一个序号是 9。

消费者可以调用 ConsumerBarrier 对象的 waitFor() 方法,传递它需要的下一个序号:

Java代码

  1. final long availableSeq = consumerBarrier.waitFor(nextSequence);
    final long availableSeq = consumerBarrier.waitFor(nextSequence);

ConsumerBarrier 返回 RingBuffer 的最大可访问序号——在上面的例子中是 12。ConsumerBarrier 持有一个 WaitStrategy 值来决定它如何等待这个序号,我现在暂时不会描述它的细节,代码里已经概括了每一种 WaitStrategy 的优点和缺点 。

接下来怎么做?

接下来,消费者会一直逛来逛去,等待更多数据被写入 Ring Buffer。并且,写入数据后消费者会收到通知——节点 9,10,11 和 12 已写入。现在序号 12 到了,消费者可以指示 ConsumerBarrier 去拿这些序号里的数据了。

拿到了数据后,消费者会更新自己的游标 (cursor)。

你应该已经感觉得到,这样做是怎样有助于抹平延迟曲线尖峰了——代替逐个逐个节点的询问“我能拿下一个数据吗?现在怎么样了?现在呢?”,消费者 Consumer 只需要简单的说“当你拿到的数字比这个要大的时候请告诉我”,函数返回值会告诉它有多少个新的数据节点可以读取。因为这些新的节点的确已经写入(Ring Buffer 本身的序号已经更新),而且消费者对这些节点的唯一操作是读而不是写,因此访问不用加锁。这样简直太好了,不仅代码可以更加安全和简单,而且不用加锁的速度超快。

另一个额外的好处是——你可以用多个消费者 Consumer 读同一个 RingBuffer, 不需要加锁,也不需要用另外的队列来协调不同的线程。这样你可以在 Disruptor 的协调下实现真正的并发数据处理。

BatchConsumer​ 是一个消费端的例子代码。如果你实现了 BatchHandler​, 你可以用 BatchConsumer 来完成上面我提到的复杂工作。它很容易实现需要成批处理节点(例如上文 9-12 的节点)的功能而不用单独读取每一个节点。

更新:注意 Disruptor 2.0 版使用了与本文不一样的命名。如果你对类名感到困惑,请阅读我的 变更总结​。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏撸码那些事

是什么影响了数据库索引选型?

上一篇文章我们介绍了索引背后的数据结构,这篇文章我们来介绍影响索引数据结构选型的因素——存储器存取。

622
来自专栏何俊林

你是否真的适合搞NDK开发?

最近很多人说,Android越来越不好找工作了,学习NDK开发会不会好点,今天就聊聊这个问题。是否应该选择学NDK? 1 哪些场景下要用到NDK开发? 跨平台的...

2215
来自专栏牛客网

C++后台腾讯WXG实习面经(已拿offer)

时间:2018年4月16日 岗位:C/C++后台开发(Linux) BG:WXG 关于我:本科大三 预计2019年毕业 一面(普通技术面) 过程:递交简历 ->...

78910
来自专栏Ceph对象存储方案

对象存储基础概念

对象存储诞生之初 谈到为什么要有对象存储,必须聊聊对象存储诞生之前的两大存储模型:块存储和文件存储。 块存储主要是将存储介质的空间整个映射给主机使用的,主机如果...

6404
来自专栏ImportSource

一次与印度兄弟就Java10中的Thread-Local Handshakes的探讨

背景 Java10引入了Thread Local Handshake功能。对此功能本人看了JEP312以后还是没有一个比较清晰的认识。为此,问了一些国内的JVM...

4969
来自专栏北京马哥教育

Python 爬虫实践:《战狼2》豆瓣影评分析

来源:hang segmentfault.com/a/1190000010473819 简介 刚接触python不久,做一个小项目来练练手。前几天看了《战狼2》...

5014
来自专栏PPV课数据科学社区

使用cProfile等工具来提高python的执行速度

摘要: 众所周知,python相较于其它语言速度较慢,但是我们可以通过优化的方法来提升效率。 本文假定你已经十分熟悉Python。 众所周知,Python是一种...

3047
来自专栏大数据杂谈

Python 爬虫实践:《战狼2》豆瓣影评分析

2495
来自专栏祝威廉

Spark Sort Based Shuffle内存分析

目前Sort Based Shuffle 是作为默认Shuffle类型的。Shuffle 是一个很复杂的过程,任何一个环节都足够写一篇文章。所以这里,我尝试换个...

1753
来自专栏向治洪

Java中的ReentrantLock和synchronized两种锁机制的对比

原文:http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html 多线程和并发性并不是什...

2415

扫码关注云+社区

领取腾讯云代金券