极致性能优化之道之消除伪共享

“不积跬步,无以至千里。”

引言

在并发编程中,伪共享(False Sharing)是一种性能问题,特别是在多核处理器上。这个问题通常出现在多个线程同时修改彼此不同但共享同一缓存行的数据。为了解决伪共享问题,我们需要采用一些技术手段,特别是在Java中,使用合适的填充技术可以有效提高性能。

什么是伪共享?

伪共享是由于缓存行的概念引起的。现代计算机架构中,缓存被分割成一些大小固定的缓存行,通常为64字节。多个线程可能在不同的核上同时访问同一缓存行的不同部分,这导致了缓存行的频繁无效化和刷新,从而降低了性能。

为什么伪共享是一个问题?

伪共享导致了缓存行的频繁无效化和刷新,从而增加了线程之间的通信开销,降低了程序的性能。在多核处理器上,不同核的缓存可能同时包含相同缓存行的不同部分,当一个核修改了其中一个部分时,其他核不得不无效化整个缓存行,即使它们修改的是不同的变量。这就是伪共享问题的本质。

Java中的填充技术

1. Volatile修饰符

在Java中,我们可以使用volatile关键字修饰共享的变量,以确保线程之间的可见性。volatile不仅会防止编译器进行指令重排序,还会禁止缓存的使用,从而避免了伪共享问题。

volatile关键字在Java中用于确保多线程之间的可见性。它的工作原理是禁止线程对被volatile修饰的变量进行本地缓存,每次访问该变量时都会从主内存中重新读取。这样可以防止线程读取过期的值,从而避免了伪共享问题。

然而,volatile并不总是适用于所有场景。它的代价是性能相对较低,因为它需要频繁地从主内存中读取变量的值。在某些高性能要求的场景下,使用其他技术可能更为合适。

public class VolatileExample {private volatile long sharedValue;// 省略其他代码public long getSharedValue() {return sharedValue;}public void setSharedValue(long value) {this.sharedValue = value;}
}

2. 缓存行填充

为了避免多个共享变量被放置在同一缓存行中,我们可以在它们之间插入一些无用的填充变量,使它们在不同的缓存行中。

缓存行填充的原理是在共享变量之间插入一些无用的填充变量,使它们位于不同的缓存行中。这样可以确保每个线程修改自己的变量时,不会影响其他线程的变量,从而避免了缓存行的频繁无效化和刷新。

在示例中,我们添加了一些padding变量,这些变量不参与实际的业务逻辑,只是为了填充缓存行。这样,即使多个线程同时访问不同的变量,它们仍然位于不同的缓存行中,不会发生伪共享问题。

public class PaddedExample {private long sharedValue;// 避免伪共享,添加填充变量private long padding1, padding2, padding3, padding4, padding5, padding6, padding7;// 省略其他代码public long getSharedValue() {return sharedValue;}public void setSharedValue(long value) {this.sharedValue = value;}
}

3. 使用@Contended注解

从Java 8开始,JVM引入了@Contended注解,用于告诉JVM在变量的周围插入填充。需要注意的是,为了启用@Contended的效果,需要在JVM启动时添加参数-XX:-RestrictContended

@Contended注解是JVM提供的一种消除伪共享的手段。通过在变量上添加该注解,JVM会在变量周围插入填充,以确保不同变量位于不同的缓存行中。

需要注意的是,为了启用@Contended的效果,需要在JVM启动时添加参数-XX:-RestrictContended。这是因为在某些情况下,默认情况下JVM可能会禁用@Contended的效果,以提高性能。

import java.util.concurrent.atomic.AtomicLong;public class ContendedExample {@sun.misc.Contended("group1")private long sharedValue;// 省略其他代码public long getSharedValue() {return sharedValue;}public void setSharedValue(long value) {this.sharedValue = value;}
}

示例与最佳实践

为了演示上述技术的使用,考虑一个多线程更新共享计数器的场景。我们将使用AtomicLong作为计数器,并比较不同技术的性能。

import java.util.concurrent.atomic.AtomicLong;public class SharedCounter {private volatile long volatileCounter;private long paddedCounter;private long contendedCounter;public SharedCounter() {volatileCounter = 0;paddedCounter = 0;contendedCounter = 0;}// 示例中的其他方法public void incrementVolatile() {volatileCounter++;}public long getVolatileCounter() {return volatileCounter;}public void incrementPadded() {paddedCounter++;}public long getPaddedCounter() {return paddedCounter;}public void incrementContended() {contendedCounter++;}public long getContendedCounter() {return contendedCounter;}
}

通过这个示例,我们可以使用不同的技术来更新计数器并比较它们的性能。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class Main {public static void main(String[] args) throws InterruptedException {SharedCounter sharedCounter = new SharedCounter();ExecutorService executorService = Executors.newFixedThreadPool(3);// 使用volatileexecutorService.submit(() -> {for (int i = 0; i < 1_000_000; i++) {sharedCounter.incrementVolatile();}});// 使用填充executorService.submit(() -> {for (int i = 0; i < 1_000_000; i++) {sharedCounter.incrementPadded();}});// 使用@ContendedexecutorService.submit(() -> {for (int i = 0; i < 1_000_000; i++) {sharedCounter.incrementContended();}});executorService.shutdown();executorService.awaitTermination(1, TimeUnit.MINUTES);System.out.println("Volatile Counter: " + sharedCounter.getVolatileCounter());System.out.println("Padded Counter: " + sharedCounter.getPaddedCounter());System.out.println("Contended Counter: " + sharedCounter.getContendedCounter());}
}

性能比较和最佳实践

在实际应用中,选择合适的技术取决于具体的需求和场景。以下是一些建议:

  1. 如果可见性是主要关注点,而性能相对较次要,可以考虑使用volatile关键字。
  2. 如果性能是关键问题,可以使用缓存行填充技术。在添加填充变量时,需要根据实际硬件架构调整填充的字节数,以确保变量位于不同的缓存行。
  3. 如果你使用的是Java 8及以上,并且JVM支持@Contended注解,可以尝试使用该注解。但请注意,启用@Contended可能会增加内存消耗,因此需要在内存和性能之间进行权衡。
  4. 在实际应用中,最佳实践是通过性能测试来评估不同技术的效果。使用性能分析工具和测量工具,例如JMH(Java Microbenchmarking Harness),来获取详细的性能数据。

综上所述,消除伪共享是一个需要综合考虑可维护性和性能的问题。选择合适的技术取决于具体的应用场景和需求,通过权衡不同技术的优缺点,可以找到最适合的解决方案。

结论

通过使用volatile、缓存行填充和@Contended等技术,我们可以有效地消除伪共享问题,提高并发程序的性能。在选择哪种技术时,需要根据具体的应用场景和性能要求进行权衡。最佳实践是根据具体情况进行性能测试,以确定哪种技术最适合你的应用。在实际开发中,根据具体情况选择最适合的优化手段,以确保高性能和可维护性的平衡。

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

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

相关文章

Redis-五种数据类型

Redis基本特性 a) 非关系型的键值对数据库&#xff0c;可以根据键以O(1) 的时间复杂度取出或插入关联值 b) Redis 的数据是存在内存中的 c) 键值对中键的类型可以是字符串&#xff0c;整型&#xff0c;浮点型等&#xff0c;且键是唯一的 d) 键值对中的值类型可以是string&a…

「torch.cosine_smilarity() = 0」引发的关于cpu与gpu精度问题的探讨

前言&#xff1a;2023年11月21日下午16:00 许&#xff0c;本篇博客记录由「torch.cosine_smilarity()计算余弦相似度计算结果为0」现象引发的关于 CPU 与 GPU 计算精度的探索。 事情的起因是&#xff0c;本人在使用 torch.cosine_smilarity() 函数计算GPU上两个特征的余弦相似度…

【迅搜02】究竟什么是搜索引擎?正式介绍XunSearch

究竟什么是搜索引擎&#xff1f;正式介绍XunSearch 啥&#xff1f;还要单独讲一下啥是搜索引擎&#xff1f;不就是百度、Google嘛&#xff0c;这玩意天天用&#xff0c;还轮的到你来说&#xff1f; 额&#xff0c;好吧&#xff0c;虽然大家天天都在用&#xff0c;但是我发现&am…

移远通信推出六款新型天线,为物联网客户带来更丰富的产品选择

近日&#xff0c;移远通信重磅推出六款新型天线&#xff0c;覆盖5G、非地面网络&#xff08;NTN&#xff09;等多种新技术&#xff0c;将为物联网终端等产品带来全新功能和更强大的连接性能。 移远通信COO张栋表示&#xff1a;“当前&#xff0c;物联网应用除了需要高性能的天线…

【libGDX】使用Mesh绘制三角形

1 Mesh 和 ShaderProgram 简介 1.1 创建 Mesh 1&#xff09;Mesh 的构造方法 public Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttribute... attributes) public Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttributes attribut…

js ::after简单实战

::after的作用是在元素后面再加个XXX样式 工作中遇到了一个表格&#xff0c;鼠标指到单元格要有个整行编辑态的效果&#xff0c;下面写个简单的demo 有人可能会说了&#xff0c;直接修改某个单元格的hover样式不就行了嘛&#xff0c;问题是如果鼠标指到单元格和单元格直接的…

Android DatePicker(日期选择器)、TimePicker(时间选择器)、CalendarView(日历视图)- 简单应用

示意图&#xff1a; layout布局文件&#xff1a;xml <?xml version"1.0" encoding"utf-8"?> <ScrollView xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"…

实验过程中的问题记录

代码&#xff1a; if args.local_rank in [-1, 0] and eval_dataset is not None and args.eval_steps > 0 and global_step % args.eval_steps 0 :metric_cur eval_fn(args, eval_dataset, model, tokenizer, global_stepglobal_step, file_prefix"eval_")当参…

IP-guard Web系统远程命令执行漏洞说明

一、漏洞说明 近期收到反馈,IP-guard Web服务器存在远程命令执行漏洞(RCE),经过分析,确认是因为Web系统的申请审批功能使用了开源插件 flexpaper 实现文件在线预览功能,此插件存在远程代码执行漏洞。 攻击者可利用 flexpaper插件漏洞,在文件预览参数中拼接其它恶意命令…

时序预测 | Pytorch实现TCN-Transformer的时间序列预测

时序预测 | Pytorch实现TCN-Transformer的时间序列预测 目录 时序预测 | Pytorch实现TCN-Transformer的时间序列预测效果一览基本介绍程序设计 效果一览 基本介绍 基于TCN-Transformer模型的时间序列预测&#xff0c;可以用于做光伏发电功率预测&#xff0c;风速预测&#xff0…

管理体系标准

管理体系标准 什么是管理体系&#xff1f; 管理体系是组织管理其业务的相互关联部分以实现其目标的方式。这些目标可能涉及许多不同的主题&#xff0c;包括产品或服务质量、运营效率、环境绩效、工作场所的健康和安全等等。 系统的复杂程度取决于每个组织的具体情况。对于某…

Vue2+Vue3

文章目录 第 1 章&#xff1a;Vue 核心1、 Vue 简介1.官网2.介绍与描述3. Vue 的特点4. 与其它 JS 框架的关联5. Vue 周边库 2、初始Vue3、模板语法1、Vue模板语法有2大类:2、插值语法和指令语法 4、数据绑定1. 单向数据绑定2. 双向数据绑定 5、el与data的两种写法1.e1有2种写法…

社会媒体营销提问常用的ChatGPT通用提示词模板

如何制定有效的社会媒体营销策略&#xff1f; 如何选择适合的社会媒体平台进行营销&#xff1f; 如何创造有吸引力的社会媒体内容&#xff0c;提高用户参与度和分享率&#xff1f; 如何运用社交媒体广告来增加品牌曝光和用户转化&#xff1f; 如何建立和维护社交媒体账号和…

外部 prometheus监控k8s集群资源

prometheus监控k8s集群资源 一&#xff0c;通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二&#xff0c;通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…

【科技素养】蓝桥杯STEMA 科技素养组模拟练习试卷01

单选题 1、生活中&#xff0c;我们经常说“有机蔬菜”相比普通蔬菜更加健康&#xff0c;这是因为 A、它们没有使用无机肥料 B、它们是有机的 C、它们没有使用肥料 D、人们对蔬菜的错误认知 答案&#xff1a;A 2、甲乙两位工人一起在工厂工作。甲的生产速度是每小时6个鼠标…

网络运维与网络安全 学习笔记2023.11.21

网络运维与网络安全 学习笔记 第二十二天 今日目标 端口隔离原理与配置、路由原理和配置、配置多路由器静态路由 配置默认路由、VLAN间通信之路由器 端口隔离原理与配置 端口隔离概述 实现报文之间的2层隔离&#xff0c;除了使用VLAN技术以后&#xff0c;还可以使用端口隔…

c语言:十进制转任意进制

思路&#xff1a;如十进制转二进制 就是不断除二求余在除二求余&#xff0c;然后将余数从下到写出来&#xff0c;这样&#xff0c;10011100就是156的二进制 这里举例一个六进制的代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<stdio.h>int main() {int …

opencv-简单图像处理

图像像素存储形式  对于只有黑白颜色的灰度图&#xff0c;为单通道&#xff0c;一个像素块对应矩阵中一个数字&#xff0c;数值为0到255, 其中0表示最暗&#xff08;黑色&#xff09; &#xff0c;255表示最亮&#xff08;白色&#xff09; 对于采用RGB模式的彩色图片&#…

「MACOS限定」 如何将文件上传到GitHub仓库

介绍 本期讲解&#xff1a;如何在苹果电脑上上传文件到github远程仓库 注&#xff1a;写的很详细 方便我的朋友可以看懂操作步骤 第一步 在电脑上创建一个新目录&#xff08;文件夹&#xff09; 注&#xff1a;创建GitHub账号、新建github仓库、git下载的步骤这里就不过多赘…

118.184.158.111德迅云安全浅谈如何避免网络钓鱼攻击

随着互联网的不断发展&#xff0c;网络钓鱼攻击也越来越猖獗&#xff0c;给个人和企业带来了巨大的经济损失和安全威胁。本文对如何防范网络钓鱼攻击提出的一些小建议 希望对大家有所帮助。 1.防止XSS&#xff08;跨站脚本攻击&#xff09;攻击 XSS攻击指的是攻击者在网站中注入…