为什么这个 Java 程序比对应的 Ada 程序快 1000 倍?
Why is this Java program 1000 times faster than its Ada equivalent?
我有两个程序,它们简单地循环十亿次并递增一个整数。我正在对这两个操作进行计时并比较两个结果。对于 Ada 程序,我使用的是 GNAT FSF 编译器。两个程序都在 Windows 上 运行。我还尝试了 运行 计算每个代码的倍数并对测量的持续时间进行平均,结果相同。
我预计会发生两件事,要么我的 Ada 程序没有正确编写(我对这门语言很陌生),要么它编写正确,但 Java 编译器正在做我不知道的代码内容。
这是 Ada 程序:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
procedure Main is
c : Integer := 1;
startTime, endTime : Time;
milliS : Duration;
begin
startTime := Clock;
while c <= 1000000000 loop
c := c + 1;
end loop;
endTime := Clock;
milliS := (endTime - startTime) * 1000;
put_line("Runtime = " & Duration'Image(milliS) & " milliseconds.");
end Main;
和Java代码:
public class Test {
public static void main(String[] args) {
int c = 1;
long start = System.nanoTime();
while (c<=1000000000) {
c = c + 1;
}
long stop = System.nanoTime();
float duration = (float) ((start - stop)/1000000.0);
System.out.println(duration);
}
}
Ada 直接编译为机器码,所以我预计它会比 Java 程序快。
Java JIT 编译器足够聪明,可以意识到循环可以被优化掉。它就是这样做的。
如果您修改 Java 版本以在最后打印出 c
的值,您将获得与(未优化的)Ada 版本大致相当的执行时间。如果使用 c
的值,则无法将循环优化掉 1。
Ada compiles straight to machine code, so I expected it to be faster than the Java program.
Java JIT 编译器也可以编译为机器代码,但不会立即编译。
1 - 直到我们得到一个 omniscient JIT 编译器,它意识到我们不关注输出:-)
我无法重现你的问题。
我用
构建了你的程序
$ gnatmake -gnata -gnato -fstack-check -gnat12 -gnatyO -gnatv -gnati1 -gnatf -gnatn -O3 main.adb
gcc-6 -c -gnata -gnato -fstack-check -gnat12 -gnatyO -gnatv -gnati1 -gnatf -gnatn -O3 main.adb
GNAT 6.3.0 20170516
Copyright 1992-2016, Free Software Foundation, Inc.
Compiling: main.adb
Source file time stamp: 2018-08-01 08:20:21
Compiled at: 2018-08-01 10:20:30
19 lines: No errors
gnatbind-6 -x main.ali
gnatlink-6 main.ali -fstack-check -O3
$
然后我运行程序使用time
检查执行时间:
$ time ./main
Runtime = 0.002000000 milliseconds.
./main 0,00s user 0,00s system 82% cpu 0,005 total
$
如果您不进行优化,那么 Ada 编译器将尝试确保您在源文本和机器代码之间尽可能接近匹配,以便轻松证明您的可执行文件执行正确的操作. - 在这种情况下,您当然应该在循环中进行 1_000_000_000 次迭代。
我有两个程序,它们简单地循环十亿次并递增一个整数。我正在对这两个操作进行计时并比较两个结果。对于 Ada 程序,我使用的是 GNAT FSF 编译器。两个程序都在 Windows 上 运行。我还尝试了 运行 计算每个代码的倍数并对测量的持续时间进行平均,结果相同。
我预计会发生两件事,要么我的 Ada 程序没有正确编写(我对这门语言很陌生),要么它编写正确,但 Java 编译器正在做我不知道的代码内容。
这是 Ada 程序:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
procedure Main is
c : Integer := 1;
startTime, endTime : Time;
milliS : Duration;
begin
startTime := Clock;
while c <= 1000000000 loop
c := c + 1;
end loop;
endTime := Clock;
milliS := (endTime - startTime) * 1000;
put_line("Runtime = " & Duration'Image(milliS) & " milliseconds.");
end Main;
和Java代码:
public class Test {
public static void main(String[] args) {
int c = 1;
long start = System.nanoTime();
while (c<=1000000000) {
c = c + 1;
}
long stop = System.nanoTime();
float duration = (float) ((start - stop)/1000000.0);
System.out.println(duration);
}
}
Ada 直接编译为机器码,所以我预计它会比 Java 程序快。
Java JIT 编译器足够聪明,可以意识到循环可以被优化掉。它就是这样做的。
如果您修改 Java 版本以在最后打印出 c
的值,您将获得与(未优化的)Ada 版本大致相当的执行时间。如果使用 c
的值,则无法将循环优化掉 1。
Ada compiles straight to machine code, so I expected it to be faster than the Java program.
Java JIT 编译器也可以编译为机器代码,但不会立即编译。
1 - 直到我们得到一个 omniscient JIT 编译器,它意识到我们不关注输出:-)
我无法重现你的问题。
我用
构建了你的程序$ gnatmake -gnata -gnato -fstack-check -gnat12 -gnatyO -gnatv -gnati1 -gnatf -gnatn -O3 main.adb
gcc-6 -c -gnata -gnato -fstack-check -gnat12 -gnatyO -gnatv -gnati1 -gnatf -gnatn -O3 main.adb
GNAT 6.3.0 20170516
Copyright 1992-2016, Free Software Foundation, Inc.
Compiling: main.adb
Source file time stamp: 2018-08-01 08:20:21
Compiled at: 2018-08-01 10:20:30
19 lines: No errors
gnatbind-6 -x main.ali
gnatlink-6 main.ali -fstack-check -O3
$
然后我运行程序使用time
检查执行时间:
$ time ./main
Runtime = 0.002000000 milliseconds.
./main 0,00s user 0,00s system 82% cpu 0,005 total
$
如果您不进行优化,那么 Ada 编译器将尝试确保您在源文本和机器代码之间尽可能接近匹配,以便轻松证明您的可执行文件执行正确的操作. - 在这种情况下,您当然应该在循环中进行 1_000_000_000 次迭代。