0

我有读取一组二进制文件的代码,这些文件基本上由许多序列化的 java 对象组成。我正在尝试通过读取线程池(Executors.newFixedThreadPool)中的文件来并行化代码

我所看到的是,当线程化时,读取的运行速度实际上比单线程慢 - 从 1.5 到 10 倍慢,具体取决于线程数。

在我的测试用例中,我实际上是从多个线程读取同一个文件(35mb),所以我不受 I/O 的任何约束。我运行的线程数不超过 CPU,并且池之间没有任何同步——即我只是独立处理一堆文件。

有谁知道线程时性能缓慢的可能原因是什么?我应该寻找什么?或者剖析问题的最佳方法是什么?我已经在类中查找了可以在线程之间共享的静态变量,但我没有看到任何变量。在线程中实例化时,其中一个java.*类的运行速度是否会明显变慢(例如java.zip.deflate我正在使用的类)?
感谢您的任何提示。

Upd:另一个有趣的提示是,当单个线程运行时,执行读取的函数的执行时间是恒定到高精度的,但是当运行多个线程时,我看到时间上有很大的变化。

4

3 回答 3

2

在我看来,当您添加多个执行相同工作的线程时,您期望java.zip.deflate35mb 的读取运行得更快。它不会。实际上,尽管您可能不受 IO 限制,但您添加的每个线程仍然会产生内核开销——缓冲区副本等。即使您完全读取内核缓冲区空间,也会产生 CPU 和处理开销。

也就是说,我很惊讶你会慢 1.5 到 10 倍。如果您的每个处理线程都在写入输出,那么显然不会缓存。

但是,我怀疑您可能会发生内存争用。如果您正在处理 Java 序列化对象流,则需要注意内存消耗,除非您经常重置它。序列化保留了大量对对象的引用,因此大的连续流可以生成大量的 GC 带宽。

我会使用 jconsole 连接到您的程序并密切关注内存选项卡。随着幸存者和旧代空间的填充,您看到非线性 CPU 影响。

于 2012-05-15T15:44:57.177 回答
0

问题是由 java.util.zip.Inflate 类引起的,该类实际上有很多同步方法(因为其中有几个使用本机代码),所以当多个线程运行时,同步方法相互竞争并制作代码非常接近顺序。

解决方案是用 GNU 类路径中的仅 java 版本替换 java.util.zip 类(例如,从这里http://git.savannah.gnu.org/cgit/classpath.git/tree/java/util/zip

于 2012-05-16T02:51:12.603 回答
0

仅仅因为所有线程工作人员都在从同一个文件中读取并不意味着它肯定不受 IO 限制。有可能。可能不是。可以肯定的是,设置您的测试用例,以便所有线程工作人员都从内存中的文件而不是磁盘中读取。

您在上面提到您认为操作系统已经缓存了文件,但是您确定文件是否以只读/共享模式打开?如果没有,那么操作系统仍然可以锁定文件以确保一次只有一个线程可以访问。

潜在相关链接:

于 2012-05-15T15:45:01.187 回答