高性能队列Disruptor

Java SDK 提供了 2 个有界队列:ArrayBlockingQueue 和 LinkedBlockingQueue,它们都是基于 ReentrantLock 实现的,在高并发场景下,锁的效率并不高。
今天我们就介绍一种性能更高的有界队列:Disruptor。

Disruptor 是一款高性能的有界内存队列,Disruptor 性能之高,取决于下面四点,下面我们分别来讲解。

1.内存分配更加合理,使用 RingBuffer 数据结构,数组元素在初始化时一次性全部创建,提升缓存命中率;对象循环利用,避免频繁 GC.

该做法利用局部性原理,时间局部性,空间局部性,cpu缓存就利用了程序局部性原理,cpu从内存中加载数据x时,会将数据x缓存到高速缓存cache中(缓存行),同时还缓存了x周围的数据(连续地址)。这样在访问周围数据时,不用再从内存中填到缓存读取。
ArrayBlockingQueue底层也是采用数组的形式存放元素,E1,E2等元素都是由生产者创建的,创建这些元素的时间基本上都是离散的,所以这些元素的内存地址大概率是不连续了。
这里你可能会问,数组的内存地址不是连续的么?数组是连续的,在里面存放的引用,E1,E2元素元素对象地址不连续。在这里插入图片描述
而Disruptor中的RingBuffer数组中的元素在初始化时是一次性全部创建的,所以这些元素的内存地址大概率是连续的,生产者每publishEvent发布Event时,不会创建Event,而是Event.set修改初始化的Event.也就是说 RingBuffer 创建的 Event 是可以循环利用的,这样还能避免频繁创建、删除 Event 导致的频繁 GC 问题。

2. 能够避免伪共享,提升缓存利用率。

伪共享就是多个cup中缓存同一个缓存行,该缓存行中有多个元素,如果修改一个元素,会使其他cpu缓存了该缓存行无效,使得其他线程访问其他元素不成功,没有很好利用cache.
比如ArrayBlockingQueue当cpu从内存中加载takeindex,会同时将putindex加载进缓存行中,当A入队操作,修改takeindex,会把缓存行写入到内存中,导致其他cpu上的缓存行失效,如果B出队,正要修改呢,缓存行失效,就得重新从内存中加载。造成缓存利用率不高。
但是ArrayBlockingQueue内部使用锁,不可能出现出队入队同时出现的情况。
在这里插入图片描述
使用缓存行填充避免伪共享

3. 采用无锁算法,避免频繁加锁、解锁的性能消耗。

对于入队操作,最关键的要求是不能覆盖没有消费的元素;对于出队操作,最关键的要求是不能读取没有写入的元素。
Disruptor使用索引来入队和出队,比如入队,如果没有足够的空余位置,就出让 CPU 使用权,然后重新计算;反之则用 CAS 设置入队索引。

//生产者获取n个写入位置
do {
  //cursor类似于入队索引,指的是上次生产到这里
  current = cursor.get();
  //目标是在生产n个
  next = current + n;
  //减掉一个循环
  long wrapPoint = next - bufferSize;
  //获取上一次的最小消费位置
  long cachedGatingSequence = gatingSequenceCache.get();
  //没有足够的空余位置
  if (wrapPoint>cachedGatingSequence || cachedGatingSequence>current){
    //重新计算所有消费者里面的最小值位置
    long gatingSequence = Util.getMinimumSequence(
        gatingSequences, current);
    //仍然没有足够的空余位置,出让CPU使用权,重新执行下一循环
    if (wrapPoint > gatingSequence){
      LockSupport.parkNanos(1);
      continue;
    }
    //从新设置上一次的最小消费位置
    gatingSequenceCache.set(gatingSequence);
  } else if (cursor.compareAndSet(current, next)){
    //获取写入位置成功,跳出循环
    break;
  }
} while (true);

4. 支持批量消费,消费者可以无锁方式消费多个消息。

### PyCharm 打开文件显示全的解决方案 当遇到PyCharm打开文件显示全的情况时,可以尝试以下几种方法来解决问题。 #### 方法一:清理缓存并重启IDE 有时IDE内部缓存可能导致文件加载异常。通过清除缓存再启动程序能够有效改善此状况。具体操作路径为`File -> Invalidate Caches / Restart...`,之后按照提示完成相应动作即可[^1]。 #### 方法二:调整编辑器字体设置 如果是因为字体原因造成的内容显示问题,则可以通过修改编辑区内的文字样式来进行修复。进入`Settings/Preferences | Editor | Font`选项卡内更改合适的字号大小以及启用抗锯齿功能等参数配置[^2]。 #### 方法三:检查项目结构配置 对于某些特定场景下的源码视图缺失现象,可能是由于当前工作空间未能正确识别全部模块所引起。此时应该核查Project Structure的Content Roots设定项是否涵盖了整个工程根目录;必要时可手动添加遗漏部分,并保存变更生效[^3]。 ```python # 示例代码用于展示如何获取当前项目的根路径,在实际应用中可根据需求调用该函数辅助排查问题 import os def get_project_root(): current_file = os.path.abspath(__file__) project_dir = os.path.dirname(current_file) while not os.path.exists(os.path.join(project_dir, '.idea')): parent_dir = os.path.dirname(project_dir) if parent_dir == project_dir: break project_dir = parent_dir return project_dir print(f"Current Project Root Directory is {get_project_root()}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值