如果并行Java程序受内存限制,如何提高性能?

时间:2012-08-29 22:16:06

标签: java multithreading optimization parallel-processing bandwidth

我写了一个并行java程序。它通常起作用:

  • 输入String input;
  • 然后input均匀地切入String inputs[numThreads];
  • 每个inputs[i]都已分配到thread_i进行处理,并生成results[i];
  • 完成所有工作线程后,main线程将results[i]合并到result

10核(物理核心)机器上的性能数据如下。

Threads#    1 thread    2 threads   4 threads   8 threads   10 threads
Time(ms)       78           41          28          21           21

注意:

  • JVM预热时间已经消除(前50次运行)。
  • 时间不包括线程开始/加入时间。

当存在超过8个线程时,内存带宽似乎成为瓶颈。

在这种情况下,如何进一步提高性能?我的并行Java程序中是否存在任何设计问题?

为了检查这个可伸缩性问题的原因,我在process(inputs[i])方法中插入了一个(无意义的计算)循环。这是新数据:

Threads#    1 thread      10 threads
Time(ms)     41000          4330

新数据显示10个线程的良好可伸缩性,这反过来证实原始(没有无意义的循环)存在内存问题,因此其可伸缩性限制为8个线程。

但无论如何要绕过这个问题,比如将数据预先加载到每个核心的本地缓存中,还是批量加载?

3 个答案:

答案 0 :(得分:6)

我发现你不太可能在这里遇到内存带宽问题。您的运行时间很可能很短,当您接近0时,您只是主要计算线程启动/关闭或热交换器编译器优化周期。从运行如此短的Java任务中获取相关的时序信息几乎毫无价值。最初运行的hotswap编译器和其他优化通常会在类的生命早期主导CPU使用率。我们的生产应用程序仅在几分钟的实时服务运行后才能稳定下来。

如果您可以通过添加更多输入数据或通过反复计算相同结果来显着增加运行时间,则可以更好地了解最佳线程数是什么。

修改

既然你已经在更长的时间内为1和10个线程添加了时间,那么我认为你不受任何约束,因为时间似乎是相当线性的 - 有一些线程开销。 41000/10 = 4100对10线程4330。

很好地演示了线程可以对CPU绑定应用程序做什么。 : - )

答案 1 :(得分:2)

您有多少个逻辑核心?

考虑一下 - 想象你有一个核心和一百个线程。要完成的工作是相同的,它不能分布在多个内核上,但现在你有大量的线程切换开销。

现在想象你说四个核心和四个线程。假设没有其他瓶颈,计算时间就会四分之一。

现在想象你有四个核心和八个线程。您计算的时间将近似四分之一,但您将添加一些线程交换开销。

请注意超线程,它可能有助于或阻碍您,具体取决于计算任务的性质。

答案 2 :(得分:0)

我会说你的损失归咎于切换线程。你有更多的线程而不是核心,没有人需要阻止更慢的进程,所以他们正在接入,做一些工作然后gettimg切换出来切换另一个。切换线程是一个昂贵的过程,鉴于其性质你似乎在做什么我本能地将线程数量限制为8(为操作系统留下两个核心),你的性能数据似乎让我感到厌烦。