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

时间:2012-08-17 01:28:53

标签: multithreading performance optimization parallel-processing memory-bandwidth

我并行化了一个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. 如果是这样,有没有办法在不改变硬件的情况下进一步提高性能?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

回答标题问题

Amdahl's Law解释说,并行化程序所获得的加速取决于程序可并行化的程度。

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

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

读取内存是否可并行化?

从硬盘驱动器

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

但是,通常并行性并不能提高读取硬盘的速度。

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

固态硬盘实际上非常擅长随机访问数据,在内存中跳转,因此使用固态硬盘保持读/写队列是一个好主意。

从RAM和缓存

了解缓存行的想法有助于避免错误共享。

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

您的问题

我假设您的时间是纳秒级,因此在计算机1上,程序耗时2.5秒,然后平稳约2秒,峰值为1.9秒。

我希望您同时运行最少的后台程序,并且您执行了几次这些测试以消除不规则性。

此外,由于Java虚拟机的即时编译(JIT),时序可能会出现异常,因此为了准确计算时间,您希望在循环中运行代码几次,并存储时间最后一次迭代。 (或预编译为本机代码)。

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

程序Memory Bound?

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

第一台电脑用了2.5秒,然后用2个线程加速了20%,但之后停留了大约2.0秒。

本身,这种加速可能只是JIT的结果,高速缓冲存储器由1个线程上的时序填充。在那之后,运行时间的任何差异可能只是噪音。

第二台计算机用了4.2秒,然后是2.8秒,然后是1.9秒,然后回到了大约2.3秒。

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

任何提高性能的方法?

在代码上使用分析器,确定代码的哪些部分占用的时间最多。

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

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

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

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