1

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

  • 它需要 aString 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 个线程。

但是无论如何要规避这个问题,例如将数据预加载到每个内核的本地缓存中,还是批量加载?

4

3 回答 3

6

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

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

编辑:

现在您已经在较长时间内添加了 1 个和 10 个线程的计时,在我看来您不受任何约束,因为计时似乎是相当线性的——有一些线程开销。41000/10 = 4100 与 10 个线程的 4330。

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

于 2012-08-29T22:18:13.537 回答
2

你有多少个逻辑核心?

考虑一下——假设你有一个核心和一百个线程。要做的工作是一样的,它不能分布在多个核心上,但是现在你有大量的线程切换开销。

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

现在想象你有四个核心和八个线程。您的计算时间大约是四分之一,但您会增加一些线程交换开销。

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

于 2012-08-29T22:39:07.603 回答
0

我会说你的损失归结为切换线程。您的线程比内核多,并且不需要为较慢的进程阻塞,因此它们会被切换进来,做一些工作,然后 gettimg 切换出来以切换另一个线程。切换线程是一个昂贵的过程,考虑到你似乎在做什么我会本能地将线程数限制为 8 个(为操作系统保留两个内核),你的性能数据似乎支持我。

于 2012-08-29T22:34:33.573 回答