1

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

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

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

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

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

我有两个问题:

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

2 回答 2

1

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

于 2012-08-17T01:34:31.360 回答
1

回答标题问题

阿姆达尔定律解释说,程序并行化所获得的加速取决于程序中有多少是可并行化的。

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

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

读取内存是否可并行化?

从硬盘

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

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

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

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

从 RAM 和缓存

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

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

你的问题

我假设您的时间以纳秒为单位,因此在计算机 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 次,以查看是否有一个部分比另一个部分按比例停止。)

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

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

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

于 2012-08-17T05:31:43.790 回答