4

你好stackoverflow用户,这是我的第一个问题,所以如果我的表达方式有任何错误,请指出,谢谢

我用 Java 和 C++ 编写了这个简单的计算函数

爪哇:

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)

结果:

爪哇:2305843005992468481 1096361110

C++:2305843005992468481 6544374300

计算结果是一样的,这很好,但是打印的 nano time 显示 Java 程序需要 1 秒,而在 C++ 中需要 6 秒来执行

我做 Java 已经有一段时间了,但是我是 C++ 新手,我的代码有什么问题吗?还是 C++ 通过简单的计算比 Java 慢的事实?

另外,我在我的 C++ 代码中使用了“register”关键字,希望它能带来性能提升,但执行时间并没有什么不同,有人可以解释一下吗?

编辑:我的错误是C++编译器设置没有优化,输出设置为x32,应用/O2 WIN64并删除DEBUG后,程序只花了0.7秒执行

JDK默认对输出进行优化,但是VC++不是这样,默认有利于编译速度,不同的C++编译器的结果也不同,有些会在编译时间内计算循环的结果,导致执行时间极短(大约 5 微秒)

注意:在适当的条件下,C++ 程序在这个简单的测试中会比 Java 表现得更好,但是我注意到许多运行时安全检查被跳过,违反了它作为“安全语言”的调试意图,我相信 C++ 在大型数组测试,因为它没有边界检查

4

3 回答 3

8

在 Linux/Debian/Sid/x86-64 上,使用 OpenJDK 7

// 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

   // 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;
}    

然后编译并test.java运行

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 ,运行会更慢

2305843005992468481
5208949116

通过查看汇编代码,g++ -O2 -fverbose-asm -S -std=c++11 test.cc 我看到编译器在编译时计算了结果:

    .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

所以你只需要在你的编译器中启用优化(或者切换到更好的编译器,比如GCC 4.9)

顺便说一句,Java 低级优化发生在JVM的JIT中。我不太了解 JAVA,但我认为我不需要打开它们。我知道在 GCC 上你需要启用优化,这当然是提前的(例如 with )-O2

PS:在这个 21 世纪,我从未使用过任何 Microsoft 编译器,因此我无法帮助您了解如何在其中启用优化。

最后,我不相信这样的微基准测试很重要。基准测试然后优化您的实际应用程序。

于 2014-07-20T06:56:46.637 回答
0

在我的系统上大约需要 0.6 秒(0.592801000 秒),英特尔 2600K,3.40ghz,使用 MSVC Express 2013,64 位模式,标准版本构建。在设置完成后将 cout 移至不包括 cout 的开销。

#include <iostream>
#include <chrono>

using namespace std;

int main()
{
    auto start = chrono::high_resolution_clock::now();
    register long long total = 0;
    for (register int i = 0; i < 2147483647; i++)
    {
        total += i;
    }
    auto finish = chrono::high_resolution_clock::now();
    cout << total << endl;
    cout << chrono::duration_cast<chrono::nanoseconds>(finish - start).count() << endl;
    return 0;
}
于 2014-07-20T20:40:50.970 回答
-1

我认为描述为什么 C/C++ 总是比 Java 快的最简单方法是了解 Java 的工作原理。

从一开始,Java 就被开发用于促进跨平台软件。在 Java 之前,必须在每个机器系列上分别编译他们的程序。即使是现在,随着各种硬件架构、公认标准和操作系统的出现,人们也无法绕过这一障碍。Java 通过其 Compiler 和 JVM 实现了这一点。编译器应用它可以进行的任何优化并将其组装成 Java 字节码,这就像已编译的优化源的简写。但是,处理器还不能理解这个字节码。

这就是 Java 虚拟机的用武之地。首先,JVM 确定它正在运行的环境并加载适当的转换表。然后字节码被读入JVM,每个代码在表中查找并翻译成环境的本机机器码,然后执行。

如您所知,每条指令都需要一点时间。但是对于已编译的 C/C++ 程序,它已经在正确的机器代码中并立即执行。

有趣的注释-出于性能原因,所有操作系统和大多数设备驱动程序都是用 C 编写的。

于 2014-08-16T21:32:08.723 回答