欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: 林斌-空想工程师

disruptor是什么">Disruptor是什么

关于 Disruptor,网络上有许多的表明和说法。这里简朴的归纳综合下。Disruptor 是一个消费者出产者行列框架,据官网先容,可以提供很是强大的机能。Disruptor 与其说为我们带来了一个框架,更多的是为我们带来了一个奇特思路的编程实践。总结来说大抵有3点。

  • 利用轮回数组的方法取代行列,利用预先填凑数据的方法来制止 GC;
  • 利用 CPU 缓存行填充的方法来制止极度环境下的数据争用导致的机能下降;
  • 多线程编程中只管制止锁争用的编码能力。
  • 上面的三点是在 Disruptor 中带来的一些能力。有些是常用的,有些是实现起来较量奇特的。

    利用轮回数组取代行列

    出产者消费者模子自然是离不开行列的。可是利用传统的行列,面临并发等问题,在机能上是否已经足够的高效?可能说是否有其他的步伐来进一步的提高机能。Disruptor 为我们提供了一个思路和实践(这个思路不是 Disruptor 创始,可是他们提供了一个好的完整实践)

    根基的轮回数组实现

    界说一个数组,长度为2的次方幂(因为计较机是二进制的,所以2次方幂可以举办并运算来取代取模运算)。设定一个数字符号暗示当前的可用的位置(可以从0开始)。当这个数字符号不绝增长到大于数组长度时举办与数组长度的并运算,获得的新数字依然在数组的长度范畴内,就又可以插入。这样就仿佛一直插入直到数组末端又再次从新开始,故而称之为轮回数组。

    一般的轮回数组有头尾两个符号位。这点和行列很像。头符号位暗示下一个可以插入的位置,尾符号位暗示下一个可以读取的位置。头符号位不能大于尾符号位一个数组长度(因为这样就插入的位置和读取的位置就重叠了会导致数据丢失),尾符号位不能便是头符号位(因为这样读取的数据实际上是上一轮的旧数据)

    预先填充提高机能

    我们知道在java中假如缔造大量的工具利用后弃用,JVM 会在适当的时候举办 GC 操纵。大量的工具 GC 操纵是很耗损时间的。所以假如可以或许制止 GC 也可以提高机能,出格是在数据交互很是频繁的时候。

    在轮回数组中,可以事先在数组中填充好数据。一旦有新数据的发生,要做的就是修改数组中某一位中的一些属性值。这样可以制止频繁建设数据和弃用数据导致的 GC。这点比起行列是要好的。

    只保存一个符号位

    多线程在行列也好,轮回数组也好,一定存在对符号位的竞争。无论是利用锁来制止竞争,照旧利用 CAS 来举办无锁算法。只要争用的环境存在,而且线程较多,昆山软件开发,城市呈现对资源的不绝耗损。争用的工具越多,争用中耗损掉的资源也就越多。为了制止这样的环境,淘汰争用的资源就是一个手段。好比在轮回数组中只保存一个符号位,也就是下一个可以写入数据位置的符号位。而尾部符号位则在各个消费者线程中生存(详细的编程手法后续细讲)。

    轮回数组在单线程中的利用

    假如确定只有一个出产者,也就是说只有一个写线程。则在轮回数组中的利用会越发简化。详细来说单线程更新数组上的符号位,那这种环境,符号位就无需回收 CAS 写的方法来确定下一个可写入的位置,直接就是在单线程内举办普通的更新即可。

    轮回数组在多线程中的利用

    假如存在多个出产者,则可写入的符号位需要用 CAS 算法来举办争夺,制止锁的利用。多个线程通过 CAS 获得独一的不斗嘴的下一个可写序号。由于需要得到序号后才气举办写入,而写入完成才可以让消费者线程举办消费。所以才得到序号后,完成写入前,必需有一种方法让消费者检测是否完成。以制止消费者拿到还未填入输入的数组位。

    为了到达这个方针,存在简朴—效率低和巨大—效率高两种方法。

    简朴可是大概效率低的方法

    利用两个符号位。

  • + prePut:暗示下一个可以供出产者放入的位置;
  • + put:暗示最后一个出产者已经放入的位置。
  • 多个出产者通过 CAS 得到 prePut 的差异的值。在得到的序号而且完成数据写入后,将 put 的值以 CAS 方法递增(好比得到的序号是7,只有 put 是6的时候才答允配置乐成),称之为宣布。这种方法存在一个缺点,假如多个线程并发写入,获取 prePut 的值不会堵塞,假设个中一个出产者在写入数据的时候稍慢,则其他的线程写入完毕也无法完成宣布。就会导致轮回期待,挥霍了 CPU 机能。

    巨大可是大概效率高的方法