以下小程序计算所有数字的总和,从1到10亿,我们用C ++和Java编写,就像我写的那样。我的理解是C ++是更快的"语言,但此代码的java版本在~.5秒内完成,对于C ++,约为3秒。
C ++(GCC编译器):
int main(){
long long x = 0;
for (long i=0;i<1000000001;i++){
x=x+i;
}
cout << x << endl;
return 0;
}
JAVA:
public class Main {
public static void main(String[] args) {
long x=0;
for (long i=0;i<1000000001;i++){
x=x+i;
}
System.out.println(x);
}
}
如何优化C ++代码以使其与JAVA版本一样快?它甚至可能吗?
答案 0 :(得分:5)
如果使用优化进行编译,那么C ++版本相当更快。
Java:
javac Main.java
$ time java Main
500000000500000000
real 0m0.727s
user 0m0.724s
sys 0m0.004s
C ++:
clang -O3 main.cpp -o cpp
$ time ./cpp
500000000500000000
real 0m0.003s
user 0m0.000s
sys 0m0.000s
我的铿锵版:
$ clang --version
clang version 4.0.0-1ubuntu1 (tags/RELEASE_400/rc1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
我的Java版本:
$ javac -version
javac 1.8.0_144
原因是优化是一个缓慢的过程;如果关闭优化,可以加快编译速度。这对于开发来说更好,所以这是Clang开发人员选择的默认值。 Java可能更快,因为它在运行时进行了更多优化。 JVM字节码 与它编译的源代码不同!
答案 1 :(得分:5)
这个问题是不该做的一个完美的例子。整个循环相当于单个赋值,任何优化编译器都知道它。所以你要测量启动程序和输出一行所需的时间。
然后,Java必须失去你想要的任何因素,因为运行Java代码包括启动JVM并且这很慢。此外,它还包括优化编译。 javac所做的只是从Java源码到Java字节码的编译,并没有尝试优化任何东西。所有优化都在运行时发生(字节码到机器代码)。 1
因此,我们可以得出结论,对于任何花费不到几秒钟的任务,Java非常慢。如果你努力的话,你可以得到20或无穷大的因子(除以零)。
更重要的结论是没有意义。如果您想获得有意义的结果,请参阅How do I write a correct micro-benchmark in Java?。
1 这适用于桌面Java。在Android上,它是不同的。
答案 2 :(得分:3)
使用-O
选项编译C代码。
在没有-O的情况下生成的程序集包含大量内存访问(慢):
main:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], 0
mov QWORD PTR [rbp-16], 0
.L3:
cmp QWORD PTR [rbp-16], 1000000000
jg .L2
mov rax, QWORD PTR [rbp-16]
add QWORD PTR [rbp-8], rax
add QWORD PTR [rbp-16], 1
jmp .L3
.L2:
使用-O生成的程序集仅使用寄存器:
main:
mov eax, 1000000001
.L2:
sub rax, 1
jne .L2
请参阅Godbolt的GCC资源管理器输出:https://godbolt.org/g/rx1Va4
编辑:在优化模式下,编译器会识别输出是常量,这就是没有添加指令的原因。请参阅Nathan的示例,其中包含输出:https://godbolt.org/g/r1PxvL