除了互斥锁或垃圾回收之外,还有哪些机制会减慢我的多线程 java 程序的速度?

2024-01-09

Problem

我有一段java代码(JDK 1.6.0._22,如果相关的话),它实现了一个无状态、无副作用的函数,没有互斥体。但是它确实使用了大量内存(我不知道这是否相关)。

过去,我曾访问过 Sun 实验室并收集了标准的“性能与线程数”曲线。由于该函数没有互斥体,因此它有一个很好的图表,尽管垃圾收集随着线程数量的增加而启动。经过一些垃圾收集调整后,我能够使这条曲线几乎平坦。

我现在正在英特尔硬件上做同样的实验。硬件有 4 个 CPU,每个 CPU 8 核,并且具有超线程。这给出了 64 个 availableProcessors()。不幸的是,“性能与线程数”的曲线对于 1、2、3 个线程来说可以很好地缩放,并且上限为 3 个线程。在 3 个线程之后,我可以将任意数量的线程放入任务中,但性能并没有提高

尝试解决问题

我的第一个想法是我很愚蠢,在某处引入了一些同步代码。通常为了解决此问题,我运行 JConsole 或 JVisualVM,并查看线程堆栈跟踪。如果我有 64 个线程以 3 的速度运行,我预计其中 61 个线程会等待输入互斥体。我没找到这个。相反,我发现所有线程都在运行:只是非常慢。

第二个想法是,也许计时框架带来了问题。我用一个虚拟函数替换了我的函数,该函数使用 AtomicLong 计数到十亿。这与线程数量的关系非常好:使用 64 个线程时,我的计数速度比使用 1 个线程快 64 倍,达到 10 亿 10,000 倍。

我想(绝望开始)也许垃圾收集需要很长时间,所以我调整了垃圾收集参数。虽然这改善了我的延迟变化,但它对吞吐量没有影响:我仍然有 64 个线程以我期望的 3 个线程的运行速度运行。

我已经下载了英特尔工具VTunes,但我的技能很弱:它是一个复杂的工具,我还不明白。我已经订购了说明书:给自己的一份有趣的圣诞礼物,但这对于解决我当前的问题来说有点太晚了

Question

  1. 我可以使用哪些工具(心理或软件)来提高我对正在发生的事情的理解?
  2. 除了互斥体或垃圾收集之外,还有哪些机制可能会减慢我的代码速度?

我有一段java代码(JDK 1.6.0._22,如果相关的话)

从那时起,性能有了很大的改进。我会尝试 Java 6 update 37 或 Java 7 update 10。

但它确实使用了大量内存

这可能意味着您访问数据的方式很重要。访问主内存中的数据可能比主缓存中的数据慢 20 倍以上。这意味着您必须保守地访问数据并充分利用您访问的每条新数据。

在 3 个线程之后,我可以将任意数量的线程放入任务中,但性能并没有提高 相反,我发现所有线程都在运行:只是非常慢。

这表明您正在最大限度地使用资源。考虑到您正在使用的内存量,最有可能被耗尽的资源是 cpu 到主内存的桥接器。我怀疑你有一个 64 线程的桥!这意味着您应该考虑可能使用更多 cpu 但改进访问内存的方式(减少随机性和增加顺序性)的方法,并在这样做时减少卷(尽可能使用更紧凑的类型)。例如我有“短小数点后两位”类型而不是浮点数,它可以使用一半的内存。

正如您所观察到的,当每个线程更新它自己的私有 AtomicLong 时,您将获得线性可扩展性。这根本不会使用CPU到主存的桥接。


来自@Marko

Peter,您知道这些多核架构如何与内存配合使用吗?

没有我想要的那么多,因为这个问题对于 Java 来说是不可见的。

每个核心都有独立的通道吗?

每个核心都有一个独立的主缓存通道。对于外部缓存,每个或 2-6 个缓存区域可能有一个通道,但在重负载下会出现大量冲突。

对于通往主存储器的桥梁,有一个非常宽的通道。这有利于长时间的顺序访问,但对于随机访问来说非常糟糕。单个线程可以通过随机读取来最大化这一点(足够随机,它们不适合外部缓存)

或者至少是独立的,只要不发生碰撞?

一旦耗尽主缓存(L1 通常为 32 KB),就会一直发生冲突。

因为否则缩放是一个大问题。

正如OP所示。大多数应用程序 a) 花费大量时间等待 IO b) 对小批量数据进行计算分配。对大量数据进行分配计算是最坏的情况。

我处理这个问题的方法是在内存中排列数据结构以进行顺序访问。我使用堆外内存,这很痛苦,但可以让您完全控制布局。 (我的源数据是内存映射以实现持久性)我通过顺序访问流式传输数据,并尝试充分利用这些数据(即,我最大限度地减少重复访问)即使使用 16 个内核,也很难假设所有这些都会被使用高效,因为我随时处理 40 GB 的源数据和大约 80 GB 的派生数据。

注意:高端 GPU 通过具有极高的内存带宽来解决此问题。高端处理器可达 250 GB/秒,而典型 CPU 约为 4-6 GB/秒。即便如此,它们更适合矢量化处理,并且它们引用的峰值性能可能很少有内存访问,例如曼德布罗特集。

http://www.nvidia.com/object/tesla-servers.html http://www.nvidia.com/object/tesla-servers.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

除了互斥锁或垃圾回收之外,还有哪些机制会减慢我的多线程 java 程序的速度? 的相关文章

随机推荐

  • Kotlin / Android Studio - 如何将变量从覆盖 fun 传递到应用程序的其余部分?

    我环顾四周 没有找到解决我的问题的好答案 在我的应用程序上 我有一个计时器 该计时器在单击后停止 我想根据剩余时间计算分数 我可以使用 millisUntilFinished 来计算分数 但我无法在我的应用程序中重用分数变量 您能帮我找到正
  • 限时试用和 Windows 认证

    如果您想对某个应用程序实施限时试用 您可能需要留下一些标志 注册表项 文件等 这样程序就不能被重新安装 是否有任何方案可以让您在完成此操作的同时仍然通过各种 Windows 认证计划 一般来说 申请必须正确 完整 从机器上卸载 这 包括删除
  • ffmpeg - 生成 moov 原子

    我目前正在使用blackmagic的prorecorder录制视频 我使用 ffmpeg 将视频即时转码为 mp4 视频容器 持续时间未知 因为我正在对 prorecorder 输出到命名管道的 ts 进行转码 我的目标是尝试使用浏览器播放
  • 如何在spark中合并两个预排序的rdd?

    我有两个大型 csv 文件 按其中一列进行了预排序 有没有办法利用它们已经排序的事实来更快地获得新的排序 RDD 而无需再次完全排序 简短的回答 不 在使用 Apache Spark 提供的排序工具时 无法利用两个输入 RDD 已经排序的事
  • jqgrid加载大数据集而不分页

    我想知道是否有更好的方法从服务器加载大型 Json 数据集 我使用 jqgrid 作为 loadonce true 我需要一次加载大约 1500 条记录 而且我不使用分页选项 有没有更好的方法来实现这一目标 先感谢您 这是我的网格代码 fu
  • 谷歌表格中填充谷歌表格的平均持续时间

    我有一个从谷歌表单自动填充的谷歌工作表 有一个包含持续时间的列 当我尝试平均这些持续时间时 我得到除以零的错误 我尝试更改单元格格式 但没有任何效果 事实上 无论我选择什么格式 它都不会改变 我认为格式是根据填充工作表的表单来锁定的 对于获
  • 将进程发送到后台并将控制权返回到我的 shell

    我正在为我的 CS 类编写一个 shell 并且该项目的一部分涉及如果用户传入 字符 则在后台运行一个进程 如果一个进程在前台运行 我只需execvp该进程并且它仍然控制着终端 因为它位于前台 但是 如果它是后台进程 我必须在开始执行进程后
  • 无法将函数的数组结果分配给数组

    我正在尝试将函数的数组结果分配给数组 如果我尝试将结果数组的一个元素分配给我的数组 它工作正常 但在尝试将整个结果数组分配给我的数组时它会返回错误 无法分配给数组 Sub test Dim lol 6 as Double lol Hehe2
  • 将存储过程传递给 sp_send_dbmail

    我在 SQL Server 2008 中使用 sp send dbmail 发送查询结果 我将查询移动到一个过程中 并尝试在 sp send dbmail 过程中使用该过程 如下所示 EXEC msdb dbo sp send dbmail
  • 如何为 Foundation 的 Orbit 图像滑块预加载图像?

    使用Zurb的Foundation 4 1 5 最新版本 轨道图像滑块 http foundation zurb com docs components orbit html效果很好 不幸的是 在最初的几秒钟里 所有图像都显示为一个巨大的项
  • 使用groovy Sql批量插入?

    如何在模拟准备好的语句时使用 groovy Sql 进行批量插入 我发现的所有示例都与以下类似 并且不使用准备好的语句 withBatch stmt gt stmt addBatch insert into table field1 fie
  • 从 Eclipse 和 Spark Context 将 Spark 应用程序作为纱线作业提交

    我已经可以提交了local来自我的 Eclipse IDE 的 Spark 作业 用 Scala 编写 但是 我想修改我的 Spark 上下文 在我的应用程序内 以便当我 运行 应用程序 在 Eclipse 内 时 作业将使用 Yarn 作
  • 从服务器导入更改后出现 GIT 错误

    我试图确定为什么网站上的功能可以在本地工作但不能远程工作 所以我的想法是下载远程站点并执行 git diff 以便发现任何差异 然而 自从我这样做以来 所有 GIT 命令都得到满足 fatal Unable to read current
  • R - 如何向 pheatmap 添加线条和文本?

    我正在使用创建热图pheatmap 函数使用以下代码 library pheatmap pheatmap data matrix 1 11 cluster rows F cluster cols F scale none show rown
  • 从用户角度来看,Jenkins 和 Hudson 最显着的区别是什么?

    距 Jenkins 与 Hudson 分手已有 10 个月左右 当查看项目主页时 我想知道 Hudson 和 Jenkins 之间到底有什么区别 从变更日志中我并没有真正学到很多东西 有很多更改 主要区别似乎是 Jenkins 发布频率更高
  • 如何正确传递子进程参数

    我正在尝试自动连接 格式正确的 mp4 视频文件的文件夹 我的问题的这个编辑版本将问题减少到了我困惑的最低水平 原始标题询问了之间的差异subprocess call and subprocess run但事实证明问题出在其他地方 Why
  • 如何在 WPF 中的 DatePicker 中获取日历

    我需要参考Calendar in a DatePicker object 我想象这很容易 DatePicker datePicker new DatePicker Calendar calendar datePicker Calendar
  • Android Studio 3.5.2 - 市场插件未加载

    Windows 防火墙允许 Android Studio 试着 关闭 Windows 防火墙 尝试使用不同的 ISP 尝试在本地安装 Flutter 插件 这些都不起作用 请帮我 我缺少什么 经过 10 个小时的搜索 以下是解决方案的步骤
  • 优雅地终止 Apache Commons Exec 进程

    我正在我的 Java 程序 在 Linux 上 中启动一个外部进程 并且我需要能够向它发送 SIGTERM 信号而不是 SIGKILL 信号exec getWatchdog destroyProcess 正在发送 有没有一种方法可以让我更优
  • 除了互斥锁或垃圾回收之外,还有哪些机制会减慢我的多线程 java 程序的速度?

    Problem 我有一段java代码 JDK 1 6 0 22 如果相关的话 它实现了一个无状态 无副作用的函数 没有互斥体 但是它确实使用了大量内存 我不知道这是否相关 过去 我曾访问过 Sun 实验室并收集了标准的 性能与线程数 曲线