初始问题:
我有一个应用程序,它使用ExecutorService来运行4个固定线程池。当我使用这种体系结构时,应用程序在Windows上运行得更快,而不是单线程体系结构。但是,当我在linux中运行ExecutorService体系结构时,我的应用程序的性能比单线程应用程序差。
两台机器上的CPU和其他硬件是相同的。我甚至试过不同的机器,结果都是一样的。我甚至试图将修复后的ThreadPool限制为3或2,但性能仍然较慢。我遗漏的变量可能是什么导致linux机器运行缓慢?
ExecutorService execSvc =
Executors.newFixedThreadPool(NUMBER_OF_PROCESSORS);
Perform perform[] = new Perform[n];
Future<?>[] future = new Future<?>[n];
for(int i=0;i<n;i++)
future = execSvc.submit(perform[i]);
for(int i=0;i<n;i++)
//To wait until all done
future[i].get();
两个操作系统都在同一台机器上运行。JAVA版本:windows 1.6.0_22,linux Open JDK1.6.0_20
编辑:
我试着在linux上添加Xincgc,在最初的几分钟里,代码运行得像预期的那样快,然后它开始快速变慢。请注意,我创建的代码块在我的应用程序中运行了无数次,这是否表明JVM GC在不同的操作系统中表现不同?
试验后:
在尝试了4台不同的linux机器之后,看起来openJDK引起了问题。我一开始不应该安装openJDK,但感谢@Alfabravo指出了这一点。
我唯一能想到的是,在这两个系统上,at的内存设置在某种程度上不同,而且在Linux早期,内存不足。以下是一些尝试:
- 增加Linux下的内存设置(duh)。
-Xmx1G
什么的 -
在收获后将每个未来分配给
null
。这可能没有什么影响,但对GC来说可能是值得的。for(int i = 0; i < n; i++) { future[i].get(); future[i] = null; }
- 不要将
Perform
对象存储在数组中。提交它们,然后忘记它们。如果您仍然需要它们,则在Future<Perform>
中返回它们,然后在使用完它们后将它们设置为null - 最好的胜利可能是不要一次提交所有的工作,而是保持100份优秀的工作或其他什么。将
Future
数组转换为一个列表,获得isDone()
或isCancelled()
的一次,并且只有在列表的大小低于某个阈值时才提交给池。你需要睡一觉才能不旋转。我最近确实这样做了,所以这里有一些示例代码:http://pastebin.com/3TkkxGYT
另一件需要考虑的事情是,如果你的Perform
任务很小,那么你可能只是在测试操作系统的上下文切换,而不是其他任何事情。但我不认为它会随着时间的推移而放缓。