首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >性能优化: C++和Java的性能没有达到预期的效果

性能优化: C++和Java的性能没有达到预期的效果
EN

Stack Overflow用户
提问于 2015-11-13 23:36:41
回答 2查看 1.2K关注 0票数 4

我编写了两个程序来实现一个简单的矩阵乘法算法,一个用C++,一个用Java。与我的预期相反,Java程序的运行速度比C++程序快2.5倍。我是C++的新手,我想建议我可以在C++程序中修改什么,以使它运行得更快。

我的程序借用了这个博客文章http://martin-thoma.com/matrix-multiplication-python-java-cpp的代码和数据。

下面是我使用的当前编译标志:

代码语言:javascript
复制
g++ -O3 main.cc    

javac Main.java

下面是当前的编译器/运行时版本:

代码语言:javascript
复制
$ g++ --version
g++.exe (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ java -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

我的电脑是一个2012年的核心i3笔记本电脑运行windows与MinGW。以下是当前的性能结果:

代码语言:javascript
复制
$ time ./a.exe < ../Testing/2000.in
507584919
real    0m36.469s
user    0m0.031s
sys     0m0.030s

$ time java Main < ../Testing/2000.in
507584919
real    0m14.299s
user    0m0.031s
sys     0m0.015s

以下是C++程序:

代码语言:javascript
复制
#include <iostream>
#include <cstdio>
using namespace std;

int *A;
int *B;
int height;
int width;

int * matMult(int A[], int B[]) {
        int * C = new int[height*width];
        int n = height;
        for (int i = 0; i < n; i++) {
            for (int k = 0; k < n; k++) {
                for (int j = 0; j < n; j++) {
                    C[width*i+j]+=A[width*i+k] * B[width*k+j];
                }
            }
        }
        return C;
}

int main() {
  std::ios::sync_with_stdio(false);
  cin >> height;
  cin >> width;
  A = new int[width*height];
  B = new int[width*height];
  for (int i = 0; i < width*height; i++) {
    cin >> A[i];
  }

  for (int i = 0; i < width*height; i++) {
    cin >> B[i];
  }

  int *result = matMult(A,B);
  cout << result[2];
}

以下是java程序:

代码语言:javascript
复制
import java.util.*;
import java.io.*;

public class Main {

    static int[] A;
    static int[] B;
    static int height;
    static int width;

public static void main(String[] args) {
    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        height = Integer.parseInt(reader.readLine());
        width = Integer.parseInt(reader.readLine());
        A=new int[width*height];
        B=new int[width*height];
        int index = 0;

        String thisLine;
        while ((thisLine = reader.readLine()) != null) {
            if (thisLine.trim().equals("")) {
                break;
            } else {
                String[] lineArray = thisLine.split("\t");
                for (String number : lineArray) {
                    A[index] = Integer.parseInt(number);
                    index++;
                }
            }
        }

        index = 0;
        while ((thisLine = reader.readLine()) != null) {
            if (thisLine.trim().equals("")) {
                break;
            } else {
                String[] lineArray = thisLine.split("\t");
                for (String number : lineArray) {
                    B[index] = Integer.parseInt(number);
                    index++;
                }
            }
        }

        int[] result = matMult(A,B);
        System.out.println(result[2]);

        reader.close();


    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static int[] matMult(int[] A, int[] B) {
        int[] C = new int[height*width];
        int n = height;
        for (int i = 0; i < n; i++) {
            for (int k = 0; k < n; k++) {
                for (int j = 0; j < n; j++) {
                    C[width*i+j]+=A[width*i+k] * B[width*k+j];
                }
            }
        }
        return C;
    }
}

下面是到2000x2000测试用例的链接:UlZnR4X9gZR7bG-ej3xf2A5vUv0wTDUW-kqFMA

下面是2x2测试用例的链接:sJzitjiFE8s

如果有任何建议来解释我在C++中做错了什么,或者为什么我的C++实现在这里运行得比Java慢得多,我将不胜感激!

编辑:正如建议的那样,我修改了程序,使它们不实际执行乘法,而只是读取数组并从每个数组中打印出一个数字。以下是这方面的性能结果。C++程序具有较慢的IO。然而,这只是造成部分差异的原因。

代码语言:javascript
复制
$ time ./IOonly.exe < ../Testing/2000.in
7
944
real    0m8.158s
user    0m0.000s
sys     0m0.046s

$ time java IOOnly < ../Testing/2000.in
7
944
real    0m1.461s
user    0m0.000s
sys     0m0.047s
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-14 00:10:51

我无法分析java执行,因为它创建了一个临时可执行模块,该模块在被“使用”后消失。但是,我假设它确实执行SSE指令以获得这个速度,或者它展开循环,如果禁用SSE指令,clang++会这样做。

但是用g++ (4.9.2)和clang++编译,我可以清楚地看到,clang优化了循环,使其使用SSE指令,而gcc不使用。因此,生成的代码要慢4倍。修改代码,使其在每个维度中使用一个恒定值为2000,使编译器“知道”高度和宽度的维度,gcc编译器还生成了大约8s (在我的机器上!)的代码,与带有“变量”值的27s相比,clang编译的代码在这里也稍微快了一些,但在噪声范围内我会说。

总体结论:编译器的质量/机敏性将极大地影响紧循环的性能。代码越复杂,变化越大,C++解决方案就越有可能生成更好的代码,在这些代码中,简单和容易编译的问题很可能作为一种规则在Java代码中更好,但不能保证。例如,我希望java编译器使用分析来确定循环的数量。

编辑:

time的结果可以用来确定文件的读取是否需要很长时间,但是您需要某种分析工具来确定实际输入是否使用了大量的CPU时间等等。

java引擎使用“即时编译器”,它使用分析来确定特定代码被击中的次数(您也可以对C++这样做,大型项目也可以这样做!),这允许它例如展开一个循环,或者在运行时确定一个循环中的迭代次数。考虑到这段代码执行2000 * 2000 * 2000循环,而当C++编译器知道值的大小时,它实际上做得更好,这告诉我们Java运行时实际上并没有做得更好(至少一开始不是这样),只是随着时间的推移,它设法提高了性能。

不幸的是,由于java运行时的工作方式,它没有留下二进制代码,所以我无法真正分析它所做的事情。

这里的关键是,您正在执行的实际操作很简单,逻辑也很简单,它只是非常多的操作,而且您使用的是一个简单的实现。例如,通过手动展开循环,Java和C++都将受益。

票数 4
EN

Stack Overflow用户

发布于 2015-11-14 11:51:20

默认情况下,C++并不比

C++作为一种语言是快速的,但是一旦您将库合并到混合中,您就会被限制在这些库的速度上。

这个标准几乎是为了性能而制定的,在此期间。标准库的编写考虑到了设计和正确性。

C++给了您优化的机会!

如果您对标准库的性能不满意,您可以也应该使用您自己的优化版本。

例如,标准的C++ IO对象在设计方面非常漂亮(流、区域设置、面、内部缓冲区),但这使得它们在性能上很糟糕。如果您是为Windows编写的,可以使用ReadFileWriteConsole作为IO的机制。

如果您切换到这些函数而不是标准库--您的程序的性能比Java高几个数量级。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33703412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档