如果程序受内存限制,并行化对性能有多大帮助



我并行化了一个Java程序。在具有 4 核的 Mac 上,以下是不同线程数的时间。

threads #   1         2          4           8          16
time 2597192200 1915988600  2086557400  2043377000  1931178200

在具有两个套接字(每个套接字有 4 个内核)的 Linux 服务器上,下面是测量的时间。

threads #   1         2          4           8          16 
time 4204436859 2760602109  1850708620  2370905549  2422668438

如您所见,加速比与线性加速相去甚远。在这种情况下,几乎没有并行化开销,例如同步或 I/O 依赖关系。

我有两个问题:

  1. 这些数据是否意味着这个Java程序是内存绑定的?
  2. 如果是这样,有没有办法在不改变硬件的情况下进一步提高性能?

回答标题问题

阿姆达尔定律解释说,并行化程序获得的加速取决于程序的可并行化程度。

我们还必须增加协调并行性的开销。

因此,我们考虑程序的哪些百分比/部分是可并行化的,以及会产生哪些开销(同步、通信、错误共享等)。

读取内存是否可并行化?

从硬盘

您可以同时从 2 个不同的硬盘驱动器读取数据而不会减慢速度。

但是,通常并行性不会加快从硬盘驱动器读取的速度。

硬盘驱动器(即带有旋转磁盘的驱动器)已优化为按顺序读取,在内存位置之间跳转会减慢整体内存传输速度。

固态驱动器实际上非常擅长随机访问数据,在内存中跳来跳去,因此使用固态驱动器保持读/写队列已满是个好主意。

从内存和缓存

了解缓存行的概念将有助于避免错误共享。

这种类型的内存操作可以有效地并行化,例如通过将数组划分为四个分区来迭代数组。

您的问题

我假设你的时间以纳秒为单位,所以在计算机 1 上,程序需要 2.5 秒,然后稳定到大约 2 秒,峰值为 1.9 秒。

我希望您同时运行最少的后台程序,并且您执行了几次这些测试以摆脱违规行为。

此外,由于 Java 虚拟机的实时编译 (JIT),计时可能会出现不规则,因此为了准确计时,您需要在循环中运行代码几次,并存储上次迭代的时间。(或预编译为本机代码)。

此外,由于程序第一次运行时,硬盘驱动器中使用的大部分数据都将移动到缓存中,因此以后的执行应该更快。(因此,要么使用循环后最后一次运行的计时以确保内存在缓存中,要么使用第一次计时,但在计时之间关闭电源并打开计算机)。

程序是否绑定内存?

仅根据您的时间安排,这很难说。

第一台计算机花了 2.5 秒,然后用 2 个线程加速了 20%,但随后保持在大约 2.0 秒。

就其本身而言,这种加速可能只是 JIT 和缓存内存由 1 线程上的计时填充的结果。之后,运行时的任何差异都可能只是噪音。

第二台计算机花了4.2秒,然后是2.8秒,然后是

1.9秒,然后又回到了大约2.3秒。

这似乎确实展示了某种类型的并行加速,但是发生了一些争用时间(内存、缓存行、同步等),如时间从 4 个线程增加到 8 个线程所证明的那样。

有什么方法可以提高性能吗?

对代码使用探查器,确定代码的哪些部分占用的时间最多。

(可以通过调试代码并中断并查看程序的位置来模拟探查器。重复 10 次,看看是否有一个部分比另一个部分按比例停止。

使用更好的算法或以更好的方式排列内存中的数据(数据结构)。

在问题中利用更多的并行性。

尝试使硬盘内存按顺序读取。也许只有一个线程从硬盘驱动器读取,然后将数据放入并发队列中,由其他线程操作。

好吧,它们暗示该算法不受 CPU 限制。 它可能受其他东西的约束 - 它可能是内存,I/O或其他东西,但它可能不受CPU限制。

相关内容

  • 没有找到相关文章

最新更新