繁体   English   中英

Java线程在处理结束时会变慢

[英]Java threads slow down towards the end of processing

我有一个Java程序,该程序接收包含文本文件列表的文本文件,并分别处理每一行。 为了加快处理速度,我使用了ExecutorService和带有24个线程的FixedThreadPool的线程。 该机器具有24个内核和48GB的RAM。

我正在处理的文本文件有250万行。 我发现对于前230万行,在CPU利用率高的情况下,一切运行良好。 但是,超过某个点(在2.3行附近),性能下降,仅使用一个CPU,而我的程序几乎停滞了。

我调查了许多原因,确保关闭了所有文件句柄,并增加了提供给JVM的内存量。 但是,无论我做了什么更改,性能始终会下降到最后。 我什至尝试处理包含较少行的文本文件,并且在处理文件结束时性能再次下降。

除了标准的Java并发库之外,该代码还利用Lucene库进行文本处理和分析。

当我不对该代码进行线程化时,性能是恒定的,并且不会退化到最后。 我知道这是在黑暗中拍摄的镜头,很难描述正在发生的事情,但是我想我只是想看看是否有人对导致这种性能下降到底有什么想法。

编辑

收到评论后,我在此处粘贴了堆栈跟踪。 如您所见,似乎没有任何线程在阻塞。 此外,进行性能分析时,如果速度变慢,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();

这听起来很像垃圾回收/内存问题。

运行Garbage Collection时,它将暂停所有线程,以便GC线程可以进行“此可收集垃圾”分析,而无需进行任何更改。 在运行GC时,您会看到1个线程处于100%的状态,其他线程则停留在0%的位置。

我会考虑添加一些Runtime.freeMemory()调用(或使用探查器)以查看GC期间是否发生了“磨碎到暂停”的情况。

我还尝试仅在文件的前10k行中运行您的程序,以查看是否可行。

我还要看看您的程序在使用StringBuilders时是否会构建过多的中间String。

在我看来,您需要分析内存使用情况。

我最初以为也是GC问题,但我不确定提供以下信息。

我什至尝试处理包含较少行的文本文件,并且在处理文件结束时性能再次下降。

我的猜测是线程没有退出,但是以某种方式被阻塞了。 我建议您进行线程转储(在* nix下或使用jstack kill -QUIT pid )并查看线程在哪里。 这将帮助您确定它们是否卡在某处。

我怀疑您的程序在运行24个线程时开始,但是随着时间的流逝,您会丢失一个,然后又丢失另一个。 尽管看起来最终性能会急剧下降,但我想知道程序是否从一开始就变得越来越慢。

  • 注意没有正确连接或IO超时的套接字。
  • 也许某种锁争用阻塞了线程?
  • Lucene可能正在做的事情导致争用或阻塞了线程。 如@GPI所述,我将尝试注释掉Lucene调用,看看问题是否消失。 同样,堆栈跟踪也会向您显示。

确定线程阻塞的位置后,您将需要解决锁定问题,向网络调用添加超时或以其他方式解决问题。

希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM