为什么Java似乎比C++执行速度更快 - 第2部分

Spe*_*ood 4 c++ java visual-studio-2010 netbeans7.0

介绍

这是我之前提到的问题的后续问题:Java似乎比C++更快地执行简单算法.为什么?.通过这篇文章,我学到了一些重要的东西:

  1. 我没有使用Ctrl + F5在Visual Studios C++ Express上编译和运行c ++代码,这导致了debuging减慢了代码执行速度.
  2. 向量与处理数据数组的指针一样好(如果不是更好).
  3. 我的C++很糟糕.^ _ ^
  4. 更好的执行时间测试是迭代,而不是递归.

我试着写一个更简单的程序,它不使用指针(或Java等价的数组),并且在执行时非常简单.即便如此,Java执行速度也比C++执行速度快.我究竟做错了什么?

码:

Java的:

 public class PerformanceTest2
 {
      public static void main(String args[])
      {
           //Number of iterations
           double iterations = 1E8;
           double temp;

           //Create the variables for timing
           double start;
           double end;
           double duration; //end - start

           //Run performance test
           System.out.println("Start");
           start = System.nanoTime();
           for(double i = 0;i < iterations;i += 1)
           {
                //Overhead and display
                temp = Math.log10(i);
                if(Math.round(temp) == temp)
                {
                     System.out.println(temp);
                }
           }
           end = System.nanoTime();
           System.out.println("End");

           //Output performance test results
           duration = (end - start) / 1E9;
           System.out.println("Duration: " + duration);
      }
 }
Run Code Online (Sandbox Code Playgroud)

C++:

#include <iostream>
#include <cmath>
#include <windows.h>
using namespace std;

double round(double value)
{
return floor(0.5 + value);
}
void main()
{
//Number of iterations
double iterations = 1E8;
double temp;

//Create the variables for timing
LARGE_INTEGER start; //Starting time
LARGE_INTEGER end; //Ending time
LARGE_INTEGER freq; //Rate of time update
double duration; //end - start
QueryPerformanceFrequency(&freq); //Determinine the frequency of the performance counter (high precision system timer)

//Run performance test
cout << "Start" << endl;
QueryPerformanceCounter(&start);
for(double i = 0;i < iterations;i += 1)
{
    //Overhead and display
    temp = log10(i);
    if(round(temp) == temp)
    {
        cout << temp << endl;
    }
}
QueryPerformanceCounter(&end);
cout << "End" << endl;

//Output performance test results
duration = (double)(end.QuadPart - start.QuadPart) / (double)(freq.QuadPart);
cout << "Duration: " << duration << endl;

//Dramatic pause
system("pause");
}
Run Code Online (Sandbox Code Playgroud)

观察:

对于1E8迭代:

C++执行= 6.45秒

Java执行= 4.64秒

更新:

根据Visual Studios,我的C++命令行参数是:

/Zi /nologo /W3 /WX- /O2 /Ob2 /Oi /Ot /Oy /GL /D "_MBCS" /Gm- /EHsc /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Release\C++.pch" /Fa"Release\" /Fo"Release\" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue
Run Code Online (Sandbox Code Playgroud)

更新2:

我使用新的round函数更改了c ++代码,并更新了执行时间.

更新3:

我找到了问题的答案,感谢Steve Townsend和Loduwijk.在将我的代码编译成汇编并对其进行评估后,我发现C++程序集创建的内存移动方式比Java程序集更多.这是因为我的JDK使用的是x64编译器,而我的Visual Studio Express C++无法使用x64架构,因此本质上速度较慢.所以,我安装了Windows SDK 7.1,并使用这些编译器编译我的代码(在发行版中,使用ctrl + F5).目前的时间比例是:

C++:~2.2 s Java:~4.6 s

现在我可以用C++编译所有代码,最后获得我的算法所需的速度.:)

Bli*_*ndy 21

这是一个安全的假设,任何时候你看到Java超越C++,特别是如此巨大的差距,你做错了什么.由于这是专门针对这种微观微观优化的第二个问题,我觉得我应该建议找一个不那么徒劳的爱好.

这回答了你的问题:你正在使用C++(实际上,你的操作系统)是错误的.至于隐含的问题(如何?),这很简单:endl刷新流,Java继续缓冲它.替换你的cout行:

cout << temp << "\n";
Run Code Online (Sandbox Code Playgroud)

你不太了解基准测试来比较这种东西(我的意思是比较单个数学函数).我建议买一本关于测试和基准测试的书.

  • 这让我想起几年前我在互联网上读过的一句话:"在比较不同语言的基准测试中,令人惊讶的结果往往源于观察者在一种语言中经验丰富而对另一种语言知之甚少或根本不知道" .这是真的. (11认同)
  • 打印8行输出到底是否需要3秒,无论是否冲洗缓冲区? (3认同)

Ste*_*end 7

你肯定不想为输出计时.删除每个循环中的输出语句并重新运行,以便更好地比较您实际感兴趣的内容.否则,您还要对输出函数和视频驱动程序进行基准测试.结果速度实际上取决于您运行的控制台窗口是否在测试时被遮挡或最小化.

确保您没有在C++中运行Debug构建.这将比Release更慢,与您启动流程的方式无关.

编辑:我在本地重现了这个测试场景,但无法得到相同的结果.修改代码(如下)以删除输出,Java需要5.40754388秒.

public static void main(String args[]) { // Number of iterations 
    double iterations = 1E8;
    double temp; // Create the variables for timing
    double start;
    int matches = 0;
    double end;
    double duration;
    // end - start //Run performance test
    System.out.println("Start");
    start = System.nanoTime();
    for (double i = 0; i < iterations; i += 1) {
        // Overhead and display
        temp = Math.log10(i);
        if (Math.round(temp) == temp) {
            ++matches;
        }
    }
    end = System.nanoTime();
    System.out.println("End");
    // Output performance test results
    duration = (end - start) / 1E9;
    System.out.println("Duration: " + duration);
}
Run Code Online (Sandbox Code Playgroud)

下面的C++代码需要5062 ms.这是Windows上的JDK 6u21和VC++ 10 Express.

unsigned int count(1E8);
DWORD end;
DWORD start(::GetTickCount());
double next = 0.0;

int matches(0);
for (int i = 0; i < count; ++i)
{
    double temp = log10(double(i));
    if (temp == floor(temp + 0.5))
    {
        ++count;
    }
}

end = ::GetTickCount();
std::cout << end - start << "ms for " << 100000000 << " log10s" << std::endl;
Run Code Online (Sandbox Code Playgroud)

编辑2:如果我更准确地从Java恢复你的逻辑,那么对于C++和Java来说几乎完全相同,这是我所期望的,因为它依赖于log10实现.

5157ms,100000000 log10s

用于100000000 log10s的5187ms(双循环计数器)

1001200 log10s为5312ms(双循环计数器,圆为fn)

  • @SpeedIsGood:`ctrl + f5无需调试即可构建`Ctrl-F5******将构建发布模式; 您需要更改为"Release"构建配置(不知道VCExpress隐藏它的位置) (3认同)