我写了一个并行 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 个线程。
但无论如何要规避这个问题,比如将数据预加载到每个核心的本地缓存中,或者批量加载?
最佳答案
我发现您这里不太可能有内存带宽问题。更有可能的是,您的运行时间太短,以至于当您接近 0 时,您主要是在为线程启动/关闭或热交换编译器优化周期计时。从运行时间如此之短的 Java 任务中获取相关的计时信息几乎毫无值(value)。最初运行的热交换编译器和其他优化通常在类生命周期的早期主导 CPU 使用率。我们的生产应用程序仅在实时服务运行几分钟后才稳定下来。
如果您可以通过添加更多输入数据或反复计算相同结果来显着增加运行时间,您可能会更好地了解最佳线程数是多少。
编辑:
现在您已经在更长的时间内为 1 个和 10 个线程添加计时,在我看来您不受任何限制,因为计时似乎是相当线性的 — 有一些线程开销。 41000/10 = 4100 对比 10 个线程的 4330。
很好地演示了线程可以对受 CPU 限制的应用程序做什么。 :-)
关于java - 如果并行 Java 程序受内存限制,如何提高性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12187282/