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

标签 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 个线程。

但无论如何要规避这个问题,比如将数据预加载到每个核心的本地缓存中,或者批量加载?

最佳答案

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

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

编辑:

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

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

关于java - 如果并行 Java 程序受内存限制,如何提高性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12187282/

相关文章:

java - JLabel 宽度在构造函数中始终返回 0。那么如果宽度超过X值,插入一个换行符?

java - Spring Boot 无法在/resources/static/images 文件夹中找到图像

java - 同步实例而不是 volatile 原语

multithreading - 使用 WaitForMultipleObjects 等待多个线程

java - Android游戏循环中的同步

java - “Activity has leaked window that was originally added here”

java - 以编程方式读取 jasper 报告

java - DDMS java 分析器显示 : java/lang/StringBuilder. <init> - 它在我的代码中的什么位置?

java - 从 Python 运行 Java jar 文件的最快方法?

Javascript 模块模式内存占用和性能