程序员并发编程Java 杂谈

并发编程框架Disruptor实战 - 核心类RingBuffe

2018-11-05  本文已影响10人  紫霞等了至尊宝五百年

squencer 可简单理解为序号
waitStrategy 是一种策略等待


LMAX Disruptor,LMAX是一个新型的交易平台,号称能够单线程每秒处理数百万的订单
对高性能编程领域的一些传统观点,有点不对劲。这是一种更好、更快地在线程间共享数据的方法

从这个站点,你可以下载到一篇解释什么是Disruptor及它为什么如此高性能的文档

首先介绍ringbuffer。我对Disruptor的最初印象就是ringbuffer。但是后来我意识到尽管ringbuffer是整个模式(Disruptor)的核心,但是Disruptor对ringbuffer的访问控制策略才是真正的关键点所在。

1 是什么?

正如名字所说的一样,它是一个环(首尾相接的环),可用做在不同线程间传递数据的buffer


RingBuffer

RingBuffer拥有一个序号,这个序号指向数组中下一个可用的元素




数组结构

如下图图片表示序号,这个序号指向数组的索引4的位置

RingBufferInitial
随着不停地填充该buffer(可能也会有相应的读取),这个序号会一直增长,直到绕过这个环

要找到数组中当前序号指向的元素,可以通过mod操作
sequence mod array length = array index

以上面的RingBuffer为例(Java的mod语法):12 % 10 = 2 简单吧!

上图中的RingBuffer只有10个槽完全是个意外
如果槽的个数是2的N次方更有利于基于二进制的计算机进行计算

2的N次方换成二进制就是1000,100,10,1这样的数字
sequence & (array length-1) = array index
比如一共有8槽,3 &(8 -1)= 3,HashMap就是用这个方式来定位数组元素的,这种方式比取模的速度更快

2 什么用呢

如果你看了维基百科里面的关于环形buffer的词条,RingBuffer实现方式,与其最大的区别在于:没有尾指针

只维护了一个指向下一个可用位置的序号
选择用环形buffer的最初原因就是想要提供可靠的消息传递,需要将已经被服务发送过的消息保存起来,这样当另外一个服务通过nak (拒绝应答信号)告诉我们没有成功收到消息时,我们能够重新发送给他们

咋看,环形buffer非常适合这个场景。它维护了一个指向尾部的序号,当收到nak(校对注:拒绝应答信号)请求,可以重发从那一点到当前序号之间的所有消息:

RingBufferReplay.png

ring buffer和常用的队列之间的区别是,不删除buffer中的数据,也就是说这些数据一直存放在buffer中,直到新的数据覆盖他们
这就是和维基百科版本相比,不需要尾指针的原因
ringbuffer本身并不控制是否需要重叠,决定是否重叠是生产者-消费者行为模式的一部分

3 真的秀!

ringbuffer采用这种数据结构,是因为它在可靠消息传递方面有很好的性能
这就够了,不过它还有一些其他的优点。

上一篇下一篇

猜你喜欢

热点阅读