为什么这个简单的 C++ 加法比等效的 Java 慢 6 倍?
你好stackoverflow用户,这是我问的第一个问题,所以如果我的表达方式有任何错误,请指出,谢谢
hello stackoverflow users, this is my first question asked, so if there are any errors in my way of expressing it, please point it out, thank you
我用 Java 和 C++ 编写了这个简单的计算函数
I wrote this simple calculation function in both Java and C++
Java:
long start = System.nanoTime();
long total = 0;
for (int i = 0; i < 2147483647; i++) {
total += i;
}
System.out.println(total);
System.out.println(System.nanoTime() - start);
C++:
auto start = chrono::high_resolution_clock::now();
register long long total = 0;
for (register int i = 0; i < 2147483647; i++)
{
total += i;
}
cout << total << endl;
auto finish = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::nanoseconds>(finish - start).count() << endl;
软件:- JDK8u11- Microsoft Visual C++ 编译器 (2013)
software: - JDK8u11 - Microsoft Visual C++ Compiler (2013)
结果:
Java:23058430059924684811096361110
Java: 2305843005992468481 1096361110
C++:23058430059924684816544374300
C++: 2305843005992468481 6544374300
计算结果是一样的,这很好然而,打印的纳米时间显示 Java 程序需要 1 秒,而在 C++ 中执行需要 6 秒
The calculation results are the same, which is good however, the nano time printed shows the Java program takes 1 second while in C++ it takes 6 seconds to execute
我已经使用 Java 有一段时间了,但我是 C++ 新手,我的代码有问题吗?还是说 C++ 在计算简单的情况下比 Java 慢?
I've been doing Java for quite some time, but I am new to C++, is there any problem in my code? or is it a fact that C++ is slower than Java with simple calculations?
另外,我在我的 C++ 代码中使用了register"关键字,希望它能带来性能提升,但执行时间根本没有区别,有人可以解释一下吗?
also, i used the "register" keyword in my C++ code, hoping it will bring performance improvements, but the execution time doesn't differ at all, could someone explain this?
我这里的错误是C++编译器设置没有优化,输出设置为x32,应用/O2 WIN64并删除DEBUG后,程序只用了0.7秒执行
My mistake here is the C++ compiler settings are not optimized, and output is set to x32, after applying /O2 WIN64 and removing DEBUG, the program only took 0.7 seconds to execute
JDK默认对输出进行优化,而VC++不是这样,默认情况下它有利于编译速度,不同的C++编译器的结果也不同,有些会在编译时计算循环的结果,导致极短执行时间(大约 5 微秒)
The JDK by default applies optimization to output, however this is not the case for VC++, which favors compilation speed by default, different C++ compilers also vary in result, some will calculate the loop's result in compile time, leading to extremely short execution times (around 5 microseconds)
注意:在合适的条件下,C++ 程序在这个简单的测试中将比 Java 执行得更好,但是我注意到许多运行时安全检查被跳过,违反了它作为安全语言"的调试意图,我相信 C++ 会更多在大型数组测试中优于 Java,因为它没有边界检查
NOTE: Given the right conditions, the C++ program will perform better than Java in this simple test, however I noticed many runtime safety checks are skipped, violating it's debug intention as a "safe language", I believe C++ will even more outperform Java in a large array test, as it does not have bound checking
在 Linux/Debian/Sid/x86-64 上,使用 OpenJDK 7 和
On Linux/Debian/Sid/x86-64, using OpenJDK 7 with
// file test.java
class Test {
public static void main(String[] args) {
long start = System.nanoTime();
long total = 0;
for (int i = 0; i < 2147483647; i++) {
total += i;
}
System.out.println(total);
System.out.println(System.nanoTime() - start);
}
}
和 GCC 4.9 与
and GCC 4.9 with
// file test.cc
#include <iostream>
#include <chrono>
int main (int argc, char**argv) {
using namespace std;
auto start = chrono::high_resolution_clock::now();
long long total = 0;
for (int i = 0; i < 2147483647; i++)
{
total += i;
}
cout << total << endl;
auto finish = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::nanoseconds>(finish - start).count()
<< endl;
}
然后用
javac test.java
java Test
我正在获取输出
2305843005992468481
774937152
在编译 test.cc
时进行优化
g++ -O2 -std=c++11 test.cc -o test-gcc
并运行 ./test-gcc
它会更快
2305843005992468481
40291
当然没有优化g++ -std=c++11 test.cc -o test-gcc
运行比较慢
Of course without optimizations g++ -std=c++11 test.cc -o test-gcc
the run is slower
2305843005992468481
5208949116
通过使用 g++ -O2 -fverbose-asm -S -std=c++11 test.cc
查看汇编代码,我看到编译器在编译时计算了结果:>
By looking at the assembler code using g++ -O2 -fverbose-asm -S -std=c++11 test.cc
I see that the compiler computed the result at compile time:
.globl main
.type main, @function
main:
.LFB1530:
.cfi_startproc
pushq %rbx #
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
call _ZNSt6chrono3_V212system_clock3nowEv #
movabsq $2305843005992468481, %rsi #,
movl $_ZSt4cout, %edi #,
movq %rax, %rbx #, start
call _ZNSo9_M_insertIxEERSoT_ #
movq %rax, %rdi # D.35007,
call _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ #
call _ZNSt6chrono3_V212system_clock3nowEv #
subq %rbx, %rax # start, D.35008
movl $_ZSt4cout, %edi #,
movq %rax, %rsi # D.35008, D.35008
call _ZNSo9_M_insertIlEERSoT_ #
movq %rax, %rdi # D.35007,
call _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ #
xorl %eax, %eax #
popq %rbx #
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE1530:
.size main, .-main
因此,您只需要在编译器中启用优化(或切换到更好的编译器,例如 海湾合作委员会 4.9)
So you just need to enable optimizations in your compiler (or switch to a better compiler, like GCC 4.9)
顺便说一下,Java 低级优化发生在 JIT 的 JITa href="http://en.wikipedia.org/wiki/JVM" rel="nofollow noreferrer">JVM.我不太了解 JAVA,但我认为我不需要打开它们.我知道在 GCC 上你需要启用优化,这当然是提前(例如使用 -O2
)
BTW on Java low level optimizations happen in the JIT of the JVM. I don't know JAVA well but I don't think I need to switch them on. I do know that on GCC you need to enable optimizations which of course are ahead of time (e.g. with -O2
)
PS:我在 21 世纪从未使用过任何 Microsoft 编译器,因此我无法帮助您在其中启用优化.
最后,我认为这样的微基准测试并不重要.然后进行基准测试来优化您的实际应用.
At last, I dont believe that such microbenchmarks are significant. Benchmark then optimize your real applications.