[英]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.