【发布时间】:2016-02-15 15:56:49
【问题描述】:
我编写了两个程序来实现一个简单的矩阵乘法算法,一个用 C++ 编写,一个用 Java 编写。与我的预期相反,Java 程序的运行速度比 C++ 程序快 2.5 倍。我是 C++ 的新手,想了解我可以在 C++ 程序中进行哪些更改以使其运行得更快的建议。
我的程序借用了这篇博文http://martin-thoma.com/matrix-multiplication-python-java-cpp的代码和数据。
以下是我正在使用的当前编译标志:
g++ -O3 main.cc
javac Main.java
以下是当前编译器/运行时版本:
$ 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 年代 core i3 笔记本电脑,运行 Windows 和 MinGW。以下是当前的性能结果:
$ 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++ 程序:
#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程序:
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 测试用例的链接:https://mega.nz/#!sglWxZqb!HBts_UlZnR4X9gZR7bG-ej3xf2A5vUv0wTDUW-kqFMA
这是一个 2x2 测试用例的链接:https://mega.nz/#!QwkV2SII!AtfGuxPV5bQeZtt9eHNNn36rnV4sGq0_sJzitjiFE8s
任何解释我在 C++ 中做错了什么,或者为什么我的 C++ 实现在这里运行比 Java 慢得多的建议,将不胜感激!
编辑:按照建议,我修改了程序,使它们实际上不执行乘法,而只是读取数组并从每个数组中打印出一个数字。以下是它的性能结果。 C++ 程序的 IO 较慢。然而,这只是部分差异。
$ 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
【问题讨论】:
-
你有没有实际测量过这两种情况下只加载文件的时间?
-
就是这样做的。将在上面发布结果。
-
这两个程序看起来都不是特别“快”。在 Java 代码中,特别是使用正则表达式似乎可以保证减慢速度。总的来说,我认为 mircobenchmarks 是个坏主意。
-
@MatsPetersson 我同意。与 Java 中的缓冲行读取相比,C++ 中的非缓冲值读取速度很可能很慢。
-
这似乎是一个愚蠢的问题,但是您总是先检查 C++ 程序,然后检查 Java 程序吗?这可能会在 Java 程序运行时将输入文件留在缓存中。
标签: java c++ performance optimization