Disruptor学习笔记
前言
以前一直听说有Disruptor这个东西,都说性能很强大,所以这几天自己也看了一下。
下面是自己的学习笔记,另外推荐几篇自己看到写的比较好的博客:
Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案
Disruptor3.0的实现细节
DIsruptor的底层性能如此牛掰
- 数据结构层面:使用环形结构、数组、内存预加载
- 单线程写方式、内存屏障
- 消除伪共享(填充缓存行)
- 序号栅栏(
SequenceBarrier
)配合使用来消除锁和CAS
高性能之道-数据结构-内存加载机制
- RingBuffer使用数组Object[] entries作为存储元素,如下图所示
高性能之道-内核-使用单线程写
- Disruptor的RingBuffer,之所以可以做到完全无锁,也是因为 ”单线程写“, 这是所有”前提的前提“。离开了这个前提条件,没有任何技术可以做到完全无锁
- Redis、Netty等等高性能技术框架的设计都是这个核心思想
高性能之道-系统内存优化-内存屏障
- 要正确的实现无锁,还需要另一个关键技术:内存屏障。
- 对应到Java语言,就是valotile变量与happens before语义。
- 内存屏障-Linux的smp_wmb()/smp_rmb()
高性能之道-系统缓存优化-消除伪共享
- 缓存系统中是以缓存行(cache line)为单位存储的
- 缓存行是2的整数幂个连续字节,一般为32-256个字节
- 最常见的缓存行大小是64个字节
- 当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行
- 就会无意中影响彼此的性能,这就是伪共享 -- 对应源码中的:
Sequence
:
Disruptor核心-Sequence
- Sequence可以看成是一个AtomicLong,用于标识进度
- 还有另外一个目的就是防止不同Sequence之间CPU缓存伪共享(False Sharing)的问题-- 对应源码中的:
Sequence
:
高性能之道-算法优化-序号栅栏机制
- 我们在生产者进行投递Event的时候,总会使用:long sequence = ringBuffer.next();
- Disruptor 3.0中,序号栅栏SequenceBarrier和序号Sequence搭配使用,协同和管理消费者与生产者的工作节奏,避免了锁和CAS的使用
- 在Disruptor3.0中,各个消费者和生产者持有自己的序号,这些序号的变化必须满足如下基本条件:-- 参见源码:
SingleProducerSequencer
a. 消费者的序号数值必须小于生产者序号数值;b. 消费者序号数值必须小于其前置(依赖关系)消费者的序号数值; c. 生产者序号数值不能大于消费者最小的序号数值以避免生产者速度过快,将还未来得及消费的消息覆盖
WatiStrategy等待策略
- Disruptor之所以可以说是高性能,其实也有一部分原因取决于它的等待策略的实现:WaitStrategy接口:
-- 查看源码BlockingWaitStrategy
-- 查看源码YieldingWaitStrategy
Disruptor核心-EventProcessor
- EventProcessor:主要时间循环,处理Disruptor中的Event,拥有消费者的Sequence
- 它有一个实现类是BatchEventProcessor,包含了event loop有效的实现,并且将回调到一个EventHandler接口的思想对象 -- 参见
BatchEventProcessor
源码解读
Disruptor:Disruptor的入口,主要封装了环形队列RingBuffer、消费者集合ConsumerRepository的引用;主要提供了获取环形队列、添加消费者、生产者向RingBuffer中添加事件(可以理解为生产者生产数据)的操作;
RingBuffer:Disruptor中队列具体的实现,底层封装了Object[]数组;在初始化时,会使用Event事件对数组进行填充,填充的大小就是bufferSize设置的值;此外,该对象内部还维护了Sequencer(序列生产器)具体的实现;
Sequencer:序列生产器,分别有MultiProducerSequencer(多生产者序列生产器) 和 SingleProducerSequencer(单生产者序列生产器)两个实现类。上面的例子中,使用的是SingleProducerSequencer;在Sequencer中,维护了消费者的Sequence(序列对象)和生产者自己的Sequence(序列对象);以及维护了生产者与消费者序列冲突时候的等待策略WaitStrategy;
Sequence:序列对象,内部维护了一个long型的value,这个序列指向了RingBuffer中Object[]数组具体的角标。生产者和消费者各自维护自己的Sequence;但都是指向RingBuffer的Object[]数组;
Wait Strategy:等待策略。当没有可消费的事件时,消费者根据特定的策略进行等待;当没有可生产的地方时,生产者根据特定的策略进行等待;
Event:事件对象,就是我们Ringbuffer中存在的数据,在Disruptor中用Event来定义数据,并不存在Event类,它只是一个定义;
EventProcessor:事件处理器,单独在一个线程内执行,判断消费者的序列和生产者序列关系,决定是否调用我们自定义的事件处理器,也就是是否可以进行消费;
EventHandler:事件处理器,由用户自定义实现,也就是最终的事件消费者,需要实现EventHandler接口;
RingBuffer
:
Sequence
:
这个里面缓存行的填充很经典,设计成前7后7 Long类型来填充,保证消除伪共享。
使用空间换时间,避免伪共享。Java8中使用@sun.misc.Contended 来消除伪共享,在运行时需要设置JVM启动参数:-XX:-RestrictContended
这里前7后7加上本身的Value值,总共是有15个Long元素,无论如何拆分,Value和预填充的Long型数据一定会处于单独的一个缓存行。
SingleProducerSequencer
这里就是用简单的if else判断,就避免了加锁,CAS的消耗,这里是使用序号栅栏,通过巧妙的算法+自旋操作来实现等待的操作。
解析如下图:
其中可以自己写代码去debug,创建ringBuffer长度为4,消费者阻塞在第0个元素的消费中。然后生产者再生产第5个元素的时候就会进行自旋等待。
BlockingWaitStrategy
BatchEventProcessor
waitFor 可以参考上面的BlockingWaitStrategy
的waitFor() 方法
Disruptor学习笔记的更多相关文章
- Disruptor学习笔记(一):基本原理和概念
一.Disruptor基本原理 在多线程开发中,我们常常遇到这样一种场景:一些线程接受用户请求,另外一些线程处理这些请求.比如日志处理中的日志输入和告警.这种典型的生产者消费者场景十分常见,而生产者消 ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
随机推荐
- 安装oracle11g时遇到INS-13001环境不满足最低要求
在安装oracle11g,点击setup.exe之后,弹出了如下提示框: 解决方法: 首先,打开你解压后的database文件夹,找到stage,然后cvu,找到cvu_prereq.xml文件,用记 ...
- 如何查看Unity的版本
打开Unity,Help->About Unity
- POJ 1228 (稳定凸包问题)
<题目链接> <转载于 >>> > 首先来了解什么是稳定的凸包.比如有4个点: 这四个点是某个凸包上的部分点,他们连起来后确实还是一个凸包.但是原始的凸包可 ...
- HDU 2844 Coins 【多重背包】(模板)
<题目连接> 题目大意: 一位同学想要买手表,他有n种硬币,每种硬币已知有num[i]个.已知手表的价钱最多m元,问她用这些钱能够凑出多少种价格来买手表. 解题分析: 很明显,这是一道多重 ...
- 条件随机场之CRF++源码详解-特征
我在学习条件随机场的时候经常有这样的疑问,crf预测当前节点label如何利用其他节点的信息.crf的训练样本与其他的分类器有什么不同.crf的公式中特征函数是什么以及这些特征函数是如何表示的.在这一 ...
- Java内存管理-程序运行过程(一)
勿在流沙住高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 相信在做Java开发的伙伴一定知道 JVM(Java Virtual Machine( ...
- 浅谈vue之动态路由匹配
在日常开发过程中,可能会遇到一些类似于新闻详情页的内容,需要把所有详情页映射到同一组件上,这是动态路由匹配的应用场景之一.在使用的过程中,也遇到过一些小坑,此篇做个简要的总结说明: 基本使用 { pa ...
- go语言学习-安装和配置
go的安装方式主要有两种,一种直接使用系统自带的软件源来安装,比如 ubuntu 可以直接使用 apt 安装,但通常这种方式安装的都不会是最新的.所以通常直接下载最新的安装包,可以到GoCN下载.下面 ...
- 多臂机测试, AB测试
bandit 强盗,土匪:恶棍:敲诈者 ['bændɪt] 多臂机 multi-armed bandit MAB 简写. one-arm bandit tiger ji 是一种自动AB测试的方 ...
- BZOJ.3140.[HNOI2013]消毒(二分图匹配 匈牙利)
题目链接 不难想到每次一定是切一片. 如果是平面,很容易想到直接做二分图匹配.对于3维的? 可以发现min(a,b,c)的最大值只有\(\sqrt[3]{n}≈17\),我们暴力枚举这一最小值代表的是 ...