我的 Java 程序使用 java.util.concurrent.Executor 运行多个线程,每个线程启动一个可运行的类,在该类中它从 C: 驱动器上的逗号分隔文本文件中读取并循环遍历行以拆分和解析将文本转换为 float ,然后将数据存储到:
static Vector
static ConcurrentSkipListMap
我的电脑是 Win 7 64bit,Intel Core i7,有 6 * 2 个内核和 24GB 内存,我注意到程序将运行 2 分钟并完成所有 1700 个文件,但 CPU 使用率只有 10% 左右到 15%,无论我分配了多少个线程:
Executor executor=Executors.newFixedThreadPool(50);
Executors.newFixedThreadPool(500) 不会有更好的 CPU 使用率或更短的时间来完成任务。没有网络流量,一切都在本地 C: 驱动器上,有足够的 RAM 供更多线程使用,当我将线程增加到 1000 时,它会出现“OutOfMemoryError”。
为什么更多的线程不会转化为更多的 CPU 使用率和更少的处理时间,为什么?
编辑:我的硬盘是 SSD 200 GB。
编辑:终于找到了问题所在,每个线程都将它的结果写入一个由所有线程共享的日志文件,我运行应用程序的次数越多,日志文件越大,它变得越慢,并且因为它是共享,这肯定会减慢进程,所以在我停止写入日志文件后,它会在 10 秒内完成所有任务!
最佳答案
OutOfMemoryError
可能来自 Java 自身对其内存使用的限制。尝试使用一些参数 here增加最大内存。
对于速度,Adam Bliss 从一个很好的建议开始。如果这是一遍又一遍的同一个文件,那么我想有多个线程尝试同时读取它可能会导致对文件锁的大量争用。更多的线程甚至意味着更多的争用,这甚至可能导致更差的整体性能。所以要避免这种情况,如果可能的话,只需加载一次文件。即使它是一个大文件,您也有 24 GB 的 RAM。您可以容纳相当大的文件,但您可能需要增加 JVM 允许的内存以允许加载整个文件。
如果正在使用多个文件,请考虑以下事实:您的磁盘一次只能读取一个文件。因此,如果线程没有花费太多时间进行处理,那么让多个线程同时尝试使用磁盘可能不会太有效。由于您的 CPU 使用率非常低,可能是线程加载了文件的一部分,然后在缓冲的部分上运行得非常快,然后花费大量时间等待文件的其余部分加载。如果您一遍又一遍地加载文件,那甚至可能仍然适用。
简而言之:磁盘 IO 可能是您的罪魁祸首。您需要努力减少它,以便线程不会过多地争用文件内容。
编辑:
进一步考虑,更有可能是同步问题。线程可能在尝试添加到结果列表时被阻止。如果访问频繁,这将导致对对象锁的大量争用。考虑做一些事情,比如让每个线程将其结果保存在本地列表中(例如 ArrayList
,它不是线程安全的),然后将所有值复制到最终的共享列表中分块以尝试减少争用。
关于java - 为什么 Java 中的多线程程序速度很慢,但不占用太多 CPU 时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17824565/