java - 服务器上的多线程应用程序比单线程慢(与 JUnit 测试不同)

标签 java multithreading performance debugging

我已将应用程序从单线程例程切换为多线程例程。

这在 JUnit 测试中工作得很好。当使用 10 线程运行时,测试需要 195 毫秒才能完成,而当仅使用一个线程运行时,应用程序需要 406 毫秒才能完成。所以显然有性能优势。

但是当在服务器上运行它时,应用程序现在比仅单线程时需要更长的时间。

基本上,我的应用程序读取 csv 文件中的一行,将其中一个值放入一组中,然后将该行打印到另一个文件中。 JUnit 测试中输入文件的大小约为 35 行长,服务器上的输入文件大小约为 6 000 000 行长。

放置这些值的集合是一个同步的HashSet,它可以包含Long对象。

我正在使用 Java VisualVM 监视我的应用程序,但不幸的是我不知道要寻找什么。

您对如何解决这场性能危机有什么建议吗?

<小时/>

P。 S.:大多数时候我的线程被标记为等待,但我不知道它们是否真的在等待,或者它们是否太快以至于 Java VisualVM 无​​法显示它。

<小时/>

为了进一步阐明我的例程:我单线程读取文件,但是一旦读取该行,我就会将结果对象传递给 Runnable ,将其放入一个集合中并将其打印到另一个集合中文件。同时读取下一行并将其传递给其他线程。

<小时/>

正如我在日志文件中看到的那样,线程正在执行某些操作,而不仅仅是等待。但存在某些跳跃,即超过100毫秒的时间段,其中什么也没有发生。

<小时/>

其中一个跳跃:

2011-04-08 12:27:16,580 DEBUG [Thread-10]  runnables.Runner - 7070927
2011-04-08 12:27:16,580 DEBUG [Thread-10]  runnables.Runner - 9058759
2011-04-08 12:27:16,580 DEBUG [Thread-10]  runnables.Runner - 7030928
2011-04-08 12:27:16,580 DEBUG [Thread-10]  runnables.Runner - 15301035
2011-04-08 12:27:16,684 DEBUG [Thread-10]  runnables.Runner - 7700929
2011-04-08 12:27:16,684 DEBUG [Thread-10]  runnables.Runner - 17116545
2011-04-08 12:27:16,685 DEBUG [Thread-10]  runnables.Runner - 4933581
2011-04-08 12:27:16,685 DEBUG [Thread-10]  runnables.Runner - 2861116

注意:当时没有发生GC。

<小时/>

正如下面的评论所写:我正在使用线程池。我的线程正在争夺*同一个输出文件。它们都写入同步方法。

<小时/>

即使我将运行池的大小减小到 1,性能仍然很糟糕。与之前的实现相比没有什么。这不是排除了 IO 依赖或线程切换等问题吗?

<小时/>

我现在已经修改了我的代码,因此在 Runnable 内部几乎没有执行任何操作。没有Set,没有书写。只有一个日志语句。但我仍然得到了那些跳跃。 所以我排除了一些人提出的书写或Set问题。当只运行一个线程时,我也得到了这些空闲时间。所以线程切换似乎也不是问题。

最佳答案

您的测试文件非常小,因此整个 I/O 堆栈中的任何预读层都可能完全读取它。这使得整个执行过程受 CPU 限制。线程越多,您就可以使用更多的 CPU,从而更快地完成任务。

真实的文件 OTOH 更长,因此问题变得受 IO 限制。 CPU 大部分时间都在等待读取数据。在单线程上,不存在争用,并且 IO 可能更加线性;而多线程版本更有可能生成大量光盘搜索(迄今为止,您可以在当今的硬件上执行的最慢的操作)

根据经验,如果您从磁盘或网络读取数据并且不对数据进行繁重处理,那么最好采用单线程。

关于java - 服务器上的多线程应用程序比单线程慢(与 JUnit 测试不同),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5594227/

相关文章:

java - 可以检查导入是否错误吗?编写自定义规则时

mysql - VPS 上的 Tomcat 和 MySql

performance - 只检查一次的语句?Haskell

performance - Redis 内存使用量比数据多 10 倍

java - 如何使用 jdbc/spring-jdbc 不使用 PGInterval 对 PostgreSQL 区间数据类型进行操作?

java - JOOQ 检查 Record 对象中的空字段?

multithreading - 如何按需启动/停止监视Delphi线程?

c# - 如何异步更新 winform?

multithreading - C++ 11 中宽松内存模型的底层机制是什么?

java - 为什么 String[] 比 char[] 占用更多空间?