初始问题:
我有一个应用程序使用 ExecutorService 来运行 4 个固定线程池。当我使用这种架构时,应用程序在 Windows 上运行得更快,而不是单线程架构。但是当我在 Linux 中运行 ExecutorService 架构时,我的应用程序的性能比单线程应用程序更差。
两台机器上的 CPU 和其他硬件是相同的。我什至尝试了不同的机器并得到了相同的结果。我什至尝试将 fixedThreadPool 限制为 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打开JDK1.6.0_20
编辑:
我尝试在 Linux 上添加 -Xincgc,似乎在开始的几分钟内代码运行速度如预期的那样快,之后它开始快速加速和减速。请看我创建的代码块在我的应用程序中运行了无数次,这是否表明 JVM GC 在不同操作系统中的行为不同?
试用后:
在尝试使用 4 台不同的 Linux 机器后,看起来 openJDK 导致了问题。我一开始就不应该安装 openJDK,但感谢@Alfabravo 指出了这一点。
最佳答案
我唯一能想到的是,这两个系统的内存设置有些不同,而且您在 Linux 领域的早期内存不足。这里有一些尝试:
- 增加 Linux 下的内存设置(duh)。
-Xmx1G
什么的 将每个 future 分配给
null
在你收获它之后。这可能影响不大,但可能值得帮助 GC。for(int i = 0; i < n; i++) { future[i].get(); future[i] = null; }
- 不要存储
Perform
数组中的对象。只需提交它们,然后忘记它们。如果您仍然需要它们,请在Future<Perform>
中归还它们完成后将它们设置为 null。 - 最好的办法可能是不要一次提交所有作业,而是保留 100 个未完成的作业或类似的东西。转
Future
将数组放入列表中并收获一次isDone()
或isCancelled()
并且只有在列表的大小低于某个阈值时才提交给池。你需要 sleep 才能不旋转。我最近确实这样做了,所以这里有一些示例代码:http://pastebin.com/3TkkxGYT
要考虑的另一件事是,如果您的 Perform
任务非常小,那么您可能只是在测试操作系统的上下文切换,而不是其他任何事情。但我不认为它会随着时间的推移自行减慢。
关于Java:Executor Service 在 linux 上运行缓慢而不是在 Windows 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9280321/