JCTools Mpsc源码详解(一)

news2024/9/20 16:49:37

Jctools介绍--jctools是一个Java开源并发非阻塞数据结构实现,其中主要实现了非阻塞Map和非阻塞queue,旨在为Java提供高性能并发数据结构实现;

jctool的特点--为什么性能高:

  1. lazyset--putOrderedObject,使用loadload内存屏障,写不会立即可见
  2. 大量的位运算
  3. 伪共享-通过pad类实现内存填充,使得index的写和element的写不会相互影响
  4. 无锁--cas循环代替锁
  5. 循环数组,避免了频繁GC和对象创建---对应的是内存回收和重分配

Jctools中的mpsc实现类即简单介绍--

  1. MpscArrayQueue
    1. 基于并发环形数据队列ConcurrentCircularArrayQueue的多生产者单消费者队列
    2. 该实现使用快速流方法从队列中进行轮询(进行微小更改以正确发布索引),
    3. 并在producer端扩展了Leslie Lamport并发队列算法(由Martin Thompson提出)。
    4. 只扩容一次,扩容至初始大小的1.5倍
       
  2. MpscBlockingConsumerArrayQueue
    1. 这是消费者端BlockingQueue的部分实现,仅在BaseMpscLinkedArrayQueue中描述的机制之上,但在本例中,保留位用于阻塞而不是调整大小。
  3. MpscChunkedArrayQueue
    1. MPSC阵列队列,从初始容量开始,在初始大小的链接块中增长到maxCapacity。只有当当前区块已满并且元素在调整大小时没有被复制时,队列才会增长,相反,指向新区块的链接会存储在旧区块中,供消费者使用。
    2. 只扩容一次,可以理解为固定大小
  4. MpscCompoundQueue
    1. 内部多个MpscArrayQueue--固定大小
    2. fastPoll 和 slowPoll---fastPoll根据线程ID来决定那个MpscArrayQueue入队,如果该队满则slowPoll---遍历MpscArrayQueue,寻找可以插入的queue;
  5. MpscGrowableArrayQueue
    1. 一个MPSC阵列队列,从 nitialCapacity开始,在链接的块中增长到maxCapacity,每次都将其大小翻倍,直到使用完整的备份阵列。
  6. MpscLinkedQueue
    1. 链表实现无界队列
  7. MpscUnboundedArrayQueue
    1. MPSC阵列队列,从初始容量开始,在初始大小的链接块中无限增长;
    2. 无界队列
  8. MpscUnboundedXaddArrayQueue
    1. 底层实现还是数组链表
    2. 与MpscUnboundArrayQueue不同的是,它的设计目的是在更多producer同时提交时提供更好的扩展

可以看出Jctools提供八种Mpsc的具体实现分别针对不同的生产者消费者场景,Jctools提供的Mpscqueue高性能的主要原因是文章开始提到的几种方案,以及对应的具体实现的一些优化技巧,本身使用还是基本的队列操作,屏蔽了底层的实现细节,具体分析几种经典的实现;

首先大概解释一下Mpscqueue中实现性能优化的几种技术方案--

  1. lazyset:
    1. Mpsc中很多值通过调用native方法putOrderedObject()来实现写入,而putOrderedObject()方法是Unsafe提供的直接内存操作的方法,大概可以理解为putOrderedObject()方法可以通过一个对象中的内存偏移量直接对内存的某个区域写入值,而根据Java内存模型来说分为工作内存和主内存,而这里putOrderedObject()直接写入的是工作内存,期待后续相关操作或依赖os来延时写入主内存,这就导致了putOrderedObject()写入的值一段时间对线程不可见(包括写入线程),但是提高了线程写入的性能;---在生产者消费者模型下,生产者一般不需要读取消息,而Mpsc下我们认为消费者也不会立即读取消息,所以对于消息写入提高了很大的性能
    2. 这里需要了解Java的内存模型,内存屏障以及Java对象内存布局相关的知识,详细可以看我其他文章
  2. 伪共享问题
    1. 现代OS CPU中一般使用多级缓存来解决CPU和内存之间的性能差异,而缓存一般加载缓存行的数据而不是只读取我们程序中需要读的对应的一个值---这里涉及到常用的缓存命中的问题
    2. 而如果不同的线程对相互相邻的变量进行读写操作,就导致了缓存对缓存行的频繁加载和卸载,导致了性能的浪费--
    3. 具体结合上图解释一下什么是伪共享:
      1. 首先,根据线程模型来说,同一个进程下的多个线程是贡献内存资源的--这就是共享
      2. 那什么叫伪共享呢,就是上边提到的线程工作内存,或者具体实现为CPU的多级缓存,每个线程有自己的工作内存,在工作内存中维护了内存中变量的副本,所以站在线程的角度来说变量并不是共享的,而是单独维护副本的;
      3. 伪共享有什么问题呢?我们知道线程维护了变量副本,但是OS提供的数据模型是线程共享模型,所以,线程中对于副本的修改最终会写回到主内存中从而同步给其他线程,达到真正的内存共享,这就设计到内存一致性协议,Java中的是MEMI;但是OS在为线程读取某个变量的值的时候并不是每次只读取或者写入一个值,而是以cacheline为单位来操作的(cacheline 一般为2的n次幂,大小为64B,128B,具体看os或者机器硬件的实现),如上图中,线程1只对变量A做读写,而线程2只对变量B做读写,但是实际内存中A和B是存储在相邻的内存空间中的,这就导致了线程1和线程2同时将AB作为一个cacheline读取到了自己的工作内存中,而由于OS对于内存一致性的维护,导致,线程1对A的修改需要写回到主存并同步给线程2,线程2对B的读写也是同理,这就导致了由于变量存储位置的关系,导致线程1和线程2逻辑上互不影响的操作实际上相互影响到了,从而导致了不必要的性能浪费;--这里需要注意的是,伪共享问题只发生在不同线程对同一cacheline中的不同变量访问的情况下---如果多个线程对同一个变量使用那就必须每次做同步操作,另外如果多个变量存在于不同的cacheline中的话也不存在伪共享问题;
      4. 那如何在避免伪共享问题呢?其实很简单,首先伪共享是OS为了提高性能使用的一种缓存命中策略,我们无法改变OS或者硬件的缓存策略,但是我们可以在代码层面改变变量的存储位置,最好的方法是我们保证大多数情况下会被加载到同一个cacheline的一组变量只被一个线程读写,但是这种情况过于复杂,涉及到并行化计算的策略,另外一种思路就是内存填充,内存填充怎么理解呢?我们在大概了解cacheline的大小的情况下,对某一个变量两边填充不会被使用的无用的数据,保证了一个cacheline中只包含了一个变量,从而使得多个线程使用不同变量的时候不会相互影响到;如下图
      5. Jctools中的Mpsc实现中就通过大量的pad类做为填充类-- 

     总结--Jctools使用无锁和unsafe类中提供的直接内存操作来提高多线程并发下的性能问题;要了解mpsc 的核心优化就要先了解内存共享相关问题;具体的Mpsc实现看后续的文章;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/909768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式系统中常见内存的划分方法

看到有小伙伴在讨论关于单片机内存的话题,今天就结合STM32给大家描述一下常见的划分区域。 在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全…

npm install 安装依赖,报错 Host key verification failed

设置 git 的身份和邮箱 git config --global user.name "你的名字" > 用户名 git config --global user.email “你的邮箱" > 邮箱进入 > 用户 > [你的用户名] > .ssh文件夹下,删除 known_hosts 文件即可 进入之后有可能会看到 known_hosts…

亿赛通电子文档安全管理系统 RCE漏洞

亿赛通电子文档安全管理系统 RCE漏洞 一、 产品简介二、 漏洞概述三、 复现环境四、 漏洞复现小龙POC检测: 五、 修复建议 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失…

【学会动态规划】 最长递增子序列(26)

目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 动态规划怎么学? 学习一个算法没有捷径,更何况是学习动态规划, 跟我…

【Django】 Task5 DefaultRouter路由组件和自定义函数

文章目录 【Django】 Task5 DefaultRouter路由组件和自定义函数1.路由组件1.1路由组件介绍1.2SimpleRouter1.3DefaultRouter1.4DefaultRouter示例1.5查看访问服务接口url 2.自定义函数 【Django】 Task5 DefaultRouter路由组件和自定义函数 Task5 主要了解了DefaultRouter路由…

如何使用LLM实现文本自动生成视频

推荐:使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 介绍 基于扩散的图像生成模型代表了计算机视觉领域的革命性突破。这些进步由Imagen,DallE和MidJourney等模型开创,展示了文本条件图像生成的卓越功能。有关这些模型内部工作的…

SpringMVC 反射型跨站点脚本攻击

解决方案&#xff1a; 服务端校验&#xff0c;添加拦截器 配置web,xml <filter><filter-name>xssFilter </filter-name><filter-class>com.fh.filter.XssFilter </filter-class></filter> XssFilter package com.fh.filter;import com…

【C++】运算符重载 | 赋值运算符重载

Ⅰ. 运算符重载 引入 ❓什么叫运算符重载&#xff1f; 就是&#xff1a;运用函数&#xff0c;将现有的运算符重新定义&#xff0c;使其能满足各种自定义类型的运算。 回想一下&#xff0c;我们以前运算的对象是不是都是int、char这种内置类型&#xff1f; 那我们自定义的“…

编写Dockerfile制作Web应用系统nginx镜像,生成镜像nginx:v1.1,并推送其到私有仓库

Docker 镜像是一个特殊的文件系统&#xff0c;除了提供容器运行时所需的程序、库、资源、配置等文件外&#xff0c;还包含了一些为运行时准备的一些配置参数&#xff08;如匿名卷、环境变量、用户等&#xff09;。镜像不包含任何动态数据&#xff0c;其内容在构建之后也不会被改…

存储系统性能优化中IOMMU的作用是什么?

一、IOMMU原理 IOMMU(Input/Output Memory Management Unit)是一种用于管理计算机内存的技术,它允许将物理内存映射到虚拟地址空间。IOMMU通过使用专用的硬件来管理和优化内存访问,从而提高系统性能和稳定性。本文将详细介绍IOMMU的原理,并介绍一些应用案例和典型的问题解…

Android13新特性之通知权限提升

Android13新特性之通知权限提升 随着移动通信的高速发展&#xff0c;保障通信的安全性变得尤为重要。在Android 13的最新版本中&#xff0c;通知权限的管理得到了进一步加强。为了实现安全的通信和确保用户的隐私&#xff0c;必须正确申请通知权限。本文将详细探讨如何在Andro…

时空智友企业流程化管控系统文件上传漏洞复现

0x01 产品简介 时空智友企业流程化管控系统是一个功能丰富、灵活可定制的企业管理工具。通过该系统&#xff0c;企业能够实现流程的自动化、协同的提升、数据的洞察和决策的优化&#xff0c;从而提高工作效率、管理水平和企业竞争力。 0x02 漏洞概述 时空智友企业流程化管控系…

Embedding 向量生成GPT数据使用相关

如果使用python3.6的版本&#xff0c;使用pycharm创建工程&#xff0c;那么默认会使用 docx包&#xff0c;这样运行程序会爆异常&#xff0c;突然想起以前请教的一个大神&#xff0c;想当 初&#xff0c;这个问题困扰了我 两天时间&#xff0c;在此记录一下&#xff1a; pytho…

ReactiveApi

reactivity api: https://v3.vuejs.org/api/reactivity-api 1. 获取响应式数据 API传入返回备注reactiveplain-object对象代理深度代理对象中的所有成员readonlyplain-object or proxy对象代理只能读取代理对象中的成员&#xff0c;不可修改refany{ value: ... }对value的访问…

华为数通方向HCIP-DataCom H12-821题库(单选题:01-20)

第01题 下面关于OSPF邻居关系和邻接关系描述正确的是 A、邻接关系由 OSPF的 DD 报文维护 B、OSPF 路由器在交换 Hello 报文之前必须建立邻接关系 C、邻居关系是从邻接关系中选出的为了交换路由信息而形成的关系 D、并非所有的邻居关系都可以成为邻接关系 答案&#xff1a;D 解析…

STM32F4X 定时器中断

STM32F4X 定时器中断 什么是定时器STM32F4X 定时器分类有关定时器的概念预分频(PSC)自动重装载值(ARR) STM32F4X定时器例程定时器相关函数定时器例程 什么是定时器 定时器(Timer)最基本的功能就是定时&#xff0c;比如定时翻转LED灯&#xff0c;定时向串口发送数据等。除此之外…

vue3 计算两个表单得到第三个表单数据

<el-formref"ruleFormRef"label-width"150px"label-suffix":":rules"rules":disabled"drawerProps.isView":model"drawerProps.rowData"><el-form-item label"云平台名称" prop"cloudId&…

HTTP和HTTPS的区别及通信原理

文章目录 HTTP特性http解决无状态的问题&#x1f36a;cookiesessiontoken 常见状态码报文和字段方法 HTTPS补充知识常见的加密方式数字摘要 &#xff08;数字指纹&#xff09; && 数字签名 加密过程 HTTP 何为http&#xff1f; http是超文本传输协议&#xff0c;Hyper…

MySQL 数据备份和数据恢复

目录 一、数据备份 1、概述 2、MySQLdump命令备份 1&#xff09;备份单个数据库中的所有表 2) 备份数据中某个或多个表 3) 备份所有数据库 4&#xff09;备份多个库 5) 只备份一个表或多个表结构 二、数据恢复 三、数据备份与恢复应用 一、数据备份 1、概述 数据备…

面试之HTTP

1.HTTP与HTTPS的区别 HTTP运行在TCP之上&#xff1b;HTTPS是运行在SSL之上&#xff0c;SSL运行在TCP之上两者使用的端口不同&#xff1a;HTTP使用的是80端口&#xff0c;HTTPS使用的是443端口安全性不同&#xff1a;HTTP没有加密&#xff0c;安全性较差&#xff1b;HTTPS有加密…