繁体   English   中英

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

[英]Multi threaded application on server slower than single threaded (unlike in JUnit tests)

我将应用程序从单线程例程切换到了多线程例程。

在JUnit测试中,这可以正常工作。 当使用10线程运行它时,测试需要195毫秒才能完成,而仅使用一个线程运行它时,应用程序则需要406毫秒才能完成。 因此,显然存在性能优势。

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

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

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

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

您对我如何解决此性能危机有任何暗示吗?


PS:大多数时候,我的线程被标记为正在等待,但是我不知道它们是否真的在等待,或者它们对于Java VisualVM来说显示它的速度是否太快。


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


正如我在日志文件中看到的那样,线程正在做一些事情,而不仅仅是等待。 但是有一些跳跃 ,周期超过100 ms,什么也没有发生。


这些跳跃之一:

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。


如以下评论中所述:我正在使用线程池。 我的线程正在同一个输出文件进行争用*。 它们都写入synchronized方法。


即使我将胎池的大小减小到一个,其性能仍然非常糟糕。 与以前的实现相比没有什么。 那不排除诸如IO依赖或线程切换之类的事情吗?


我现在修改了我的代码,以便在Runnable几乎什么也没做。 没有Set ,没有写作。 仅一个日志语句。 但我仍然得到了那些jumps 因此,我排除了某些人提出的写作或Set问题。 当只运行一个线程时,我也得到了这些空闲时间。 因此线程切换似乎也不是问题。

您的测试文件非常小,因此整个I / O堆栈中的任何预读层都可能完全读取了该文件。 这使整个执行CPU受到限制。 使用更多线程,您将使用更多CPU,并更快地完成任务。

实际文件OTOH更长,因此问题变得受IO约束。 CPU大部分时间都在等待读取数据。 在单个线程上,没有争用,并且IO可能更加线性。 而多线程版本更有可能产生大量磁盘寻道(到目前为止,您可以在当今的硬件上执行的最慢的操作)

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

您要引用的“跳转”是线程之间的切换时间。 由于总体执行时间受到限制,因此线程数越多,一个线程的执行时间就会越短。 如果您有许多线程,则调度程序最终会切换线程,并且没有线程会起作用。 从一个线程切换到另一个线程需要花费一定的固定时间。 如果您的线程不使用一个以上的内核并且执行完全相同的操作,那么在将多线程与单线程进行比较时,您的速度将会降低。

我不确切知道问题出在哪里,但似乎是由于执行Executor接口的错误实现引起的。

我正在使用

ExecutorService executor = Executors.newFixedThreadPool(nThreads);

而且一切正常。

  • 单线程例程的持续时间: 17.12分钟
  • 10线程例程的持续时间: 13.45分钟

我发现了一段不好的代码:

Thread.sleep(100);

在线程队列已满时被调用。

暂无
暂无

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

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