【发布时间】:2013-04-10 11:33:02
【问题描述】:
我有一个 Java 程序,它接收一个包含文本文件列表的文本文件,并分别处理每一行。为了加快处理速度,我使用带有 24 个线程的 FixedThreadPool 的 ExecutorService 线程。该机器有 24 个内核和 48GB 内存。
我正在处理的文本文件有 250 万行。我发现对于前 230 万行左右的内容,在 CPU 利用率很高的情况下运行得非常好。但是,超过某个点(大约 2.3 行),性能下降,只使用一个 CPU,我的程序几乎停止运行。
我调查了许多原因,确保我的所有文件句柄都已关闭,并增加了提供给 JVM 的内存量。然而,无论我改变什么,性能总是会在最后下降。我什至尝试过包含较少行的文本文件,但在处理文件结束时性能再次下降。
除了标准的 Java 并发库之外,代码还利用 Lucene 库进行文本处理和分析。
当我不线程化这段代码时,性能是恒定的,并且不会在最后退化。我知道这是在黑暗中拍摄,很难描述发生了什么,但我想我想看看是否有人对最终导致性能退化的原因有任何想法。
编辑
在收到 cmets 后,我粘贴了堆栈跟踪 here。如您所见,似乎没有任何线程正在阻塞。此外,在进行分析时,当事情变慢时,GC 并没有达到 100%。事实上,大部分时间 CPU 和 GC 利用率都为 0%,CPU 偶尔会出现峰值以处理一些文件,然后再次停止。
执行线程的代码
BufferedReader read = new BufferedReader(new FileReader(inputFile));
ExecutorService executor = Executors.newFixedThreadPool(NTHREADS);
String line;
while ((line = read.readLine()) != null) { //index each line
Runnable worker = new CharikarHashThreader(line, bits, minTokens);
executor.execute(worker);
}
read.close();
【问题讨论】:
-
您是否在分析器中检查过泄漏等情况?你确定没有什么东西可以让你的线程死锁吗?你能给我们看一些代码吗?
-
所以还有 200k 行在排队,它变慢了吗?您是否看过内存以确保它不在 GC 地狱中。您是一次排队排队还是排队?
-
您绝对应该使用大小有限的
BlockingQueue,而不是一次将所有行都排队。 -
正如@Gray 所说,当 JVM 在一个 CPU 的 100% 处停止时,GC 似乎是一个合理的猜测......缺少分析,您是否尝试过关闭 Lucene 以查看减速是否与你的那部分代码?您是否确保您没有在某种集合中使用非恒定时间的 put/remove/get 操作堆积操作? (例如,搜索 LinkedList 的特定元素,弹出 ArrayList 的随机元素,...)
-
我也尝试过一百万行,但在某些时候它也会变慢。基于所有的 cmets,这绝对是一个 GC 问题。我将研究这里提出的一些建议,并在更多实验后报告。谢谢!
标签: java multithreading lucene java.util.concurrent