为什么java编译上的并行执行会在时间上呈线性增长

Bhu*_*van 27 java linux cpu javac linux-kernel

time javac Main.java                                      --> 0m1.050s
time javac Main.java & javac Main.java                    --> 0m1.808s
time javac Main.java & javac Main.java & javac Main.java  --> 0m2.690s
time javac Main.java & ... 8 time                         --> 0m8.309s
Run Code Online (Sandbox Code Playgroud)

当我们javac并行运行命令并且每次增加javac命令时~1 sec都会添加所有javac命令来完成.

为什么线性增长是时间?

javac运行过程中的所有过程都涉及某种类型locks,如果是,如何克服它以便不会在时间上有线性增长


PS:上面我已经试过上single core machine,double core machine,4 core machine都表现出相同的行为.

PS2:环境RedHat7,javac 1.7.0_79

Kev*_*man 27

java编译器已经处理了在可用处理器之间划分其工作,即使只编译单个文件也是如此.因此,并行运行单独的编译器实例不会产生您期望的性能提升.

为了证明这一点,我在一个名为的文件中生成了一个大的(100万行,10,000个方法)java程序Main1.java.然后,作为由其他副本Main2.java通过Main8.java.编译时间如下:

单文件编译:

time javac Main1.java &    --> (real) 11.6 sec
Run Code Online (Sandbox Code Playgroud)

看着这个单个文件编译top显示处理器使用率大多在200-400%范围内(表示多CPU使用率,每CPU 100%),偶尔会出现700%范围内的峰值(此机器上的最大值为800%,因为有8个处理器).

接下来,两个文件同时:

time javac Main1.java &    --> (real) 14.5 sec
time javac Main2.java &    --> (real) 14.8 sec
Run Code Online (Sandbox Code Playgroud)

所以编译两个只花了14.8秒,编译一个花了11.6秒.这绝对是非线性的.很明显,通过查看top这些运行时,每个java编译器一次只能利用最多四个CPU(偶尔会出现高峰).因此,两个编译器遇到了八个CPU,大多数是彼此并行的.

接下来,同时有四个文件:

time javac Main1.java &    --> (real) 24.2 sec
time javac Main2.java &    --> (real) 24.6 sec
time javac Main3.java &    --> (real) 25.0 sec
time javac Main4.java &    --> (real) 25.0 sec
Run Code Online (Sandbox Code Playgroud)

好的,我们已经碰壁了.我们不能再对编译器进行并行化.四个文件花了25秒,两个花了14.8.那里有一点优化,但它主要是线性时间增加.

最后,八个同时:

time javac Main1.java &    --> (real) 51.9 sec
time javac Main2.java &    --> (real) 52.3 sec
time javac Main3.java &    --> (real) 52.5 sec
time javac Main4.java &    --> (real) 53.0 sec
time javac Main5.java &    --> (real) 53.4 sec
time javac Main6.java &    --> (real) 53.5 sec
time javac Main7.java &    --> (real) 53.6 sec
time javac Main8.java &    --> (real) 54.6 sec
Run Code Online (Sandbox Code Playgroud)

这实际上比线性更糟糕,因为8个花了54.6秒而4个只花了25.0秒.

因此,我认为所有这一切的结果是要相信编译器会在尝试优化您在可用CPU资源上提供的工作方面做得不错,并且尝试手动添加额外的并行化将受到限制(如果有的话)效益.

编辑:

作为参考,我在Oracle的bug数据库中找到了两个关于增强javac以利用多个处理器的条目:

  • @Ryan:我的分析旨在证明 javac 确实是多线程的,并且在跨可用处理器分配工作方面做得很好。这并不意味着在某些情况下您无法通过并行运行多个实例来获得更好的性能,但您不应期望像提问者所期望的那样获得时间/N 类型的改进。FWIW,我连续运行了 8 个编译,花了 89 秒。然后尝试了一个“javac *.java”,它花费了 56 秒,这非常接近并行运行它们的 54 秒。另请参阅我之前的评论 - 较小的文件会产生类似的结果。 (2认同)