为什么MATLAB在生成随机数方面比C++快?

3

我已经使用MATLAB一段时间来进行我的项目,但我几乎没有C++的经验。

我需要速度,听说C++比MATLAB更有效率和更快。所以我尝试了这个:

我在MATLAB中使用rand(5000,5000)创建了一个随机数矩阵。

在C++中,我初始化了一个二维向量,并创建了两个for循环,每个循环都循环了5000次。MATLAB比C++快4-5倍,所以我认为这是因为MATLAB并行执行向量化代码,然后我使用parallel_for编写了C++代码。以下是代码:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <ppl.h>
using namespace std;
using namespace concurrency;
int main();
{
    int a = 5000, b = 5000, j, k;
    vector< vector<int> > vec(a, vector<imt>(b));
    parallel_for(int(0), a, [&](int i) {
        for (j = 0; j <b; j++)
        {
            vec[i][j] = rand();
        }
    });
}

所以上面的代码比MATLAB的rand(5000,5000)快大约25%。然而,C++使用了100%的CPU,而MATLAB只使用了30%的CPU。
所以我通过运行3个实例的rand(5000,5000)来强制MATLAB使用所有的CPU,并将所需时间除以3。这使得MATLAB比C++快两倍。
我想知道我错过了什么?我知道这只是一个小例子,但我需要一个答案来确保将我的代码移植到C++。
当前状态:
当我编写没有parallel_for的C++代码时,我获得了与MATLAB相同的CPU使用率下一半的速度。然而,回答问题的人说它们几乎相同。我不明白我错过了什么。
以下是优化菜单的快照:enter image description here

2
可能与此无关,只是好奇:您是否尝试使用大小为25000的一维向量,并在执行期间将其视为二维向量? - user2486888
6
我需要一个确切的答案来确定是否将我的代码移植到C++。停止!不要这样做。大多数Matlab的核心计算例程已经用C++(或其他编译语言)编写,它们将比你自己编写的任何东西都更快。如果你想编写更快的C++,则还需要将许多例程变成多线程的形式。在SO上有许多与编写比Matlab更快的代码相关的问题和答案,但通常这种追求是没有用的。 - High Performance Mark
4
他说:“我已经使用Matlab和C++大约10年了。”而你承认:“我几乎没有C++的经验。”这是我论述的一部分——也许需要你(或我)用C ++花费10年的时间才能编写比Matlab提供的核心计算例程更快的代码。但这取决于你。 - High Performance Mark
2
你可能会对Armadillo库感兴趣。 - Chris Drew
3
(1) rand()很差劲。 (2) 我认为C语言中的rand()会锁定全局随机数生成器状态,这会破坏你的并行性。给每个线程一个自己的random_device。参见https://dev59.com/E2w05IYBdhLWcg3weBzv。 - peterchen
显示剩余14条评论
4个回答

2
当您在Matlab中调用rand(5000,5000)时,Matlab通过调用Intel MKL库来执行该命令,该库是用大量手写汇编语言编写的高度优化的C / C ++库。
MKL应该比任何直接使用C ++实现更快,但Matlab调用外部库会有一定开销。净结果是,对于较小的随机数生成(例如小于1K),普通的C / C ++实现将更快,但对于较大的尺寸,Matlab将从超级优化的MKL中受益。

2
这可能不是答案,但是有一个小提示。由于使用了向量,比较可能有点不公平。
下面是我写的一个比较。两者都占用四个可用线程中的大约100%。在这两种情况下,我创建了5000x5000个随机数字,并对其进行100次计时。
Matlab
function stackoverflow

tic
for i=1:100
    A =rand(5000);
end
toc

运行时间:约27.9秒

C++

#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <ctime>

using namespace std;


int main(){

    int N = 5000;
    double ** A = new double*[N];
    for (int i=0;i<N;i++)
        A[i] = new double[N];


    srand(time(NULL));

    clock_t start = clock();
    for (int k=0;k<100;k++){
        for (int i=0;i<N;i++){
            for (int j=0;j<N;j++){
                A[i][j] = rand();
            }
        }
    }

    cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;

}

运行时间:约28.7秒

因此,这两个示例的运行速度几乎相同。


我只是没有更改地使用了相同的注释。Matlab需要38秒,而C++需要80多秒才能完成。我错过了什么?我正在使用Visual C++作为我的IDE。 - Serdar Oztetik
我只是在 Linux 机器上使用 g++ filename.c - Thomas
@ChrisDrew 是的,我正在使用发布模式并手动运行exe文件。 - Serdar Oztetik
2
这两个随机数生成器是完全不同的算法,具有不同的输出和统计数据。Matlab基于Mersenne Twister的rand函数产生(0,1)之间的变量。C++基于线性同余生成器的rand函数产生[0,RAND_MAX]之间的变量。比较它们是没有意义的。 - horchler

1

在查看@sonystarmap的答案之后,我添加了几种容器类型:double*vector<double>vector<vector<double>>。我还添加了测试,其中“指针容器”被memset,因为vector初始化所有内存。

C++代码是使用以下优化标志编译的:-O3 -march=native

结果:

Matlab:经过28.457788秒。

C++:

T=23844.2ms

T=25161.5ms

T=25154毫秒

T=24197.3ms

T=24235.2ms

T=24166.1ms

我基本上找不到你提到的大收益。
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <ctime>
#include <vector>
#include <cstring>

using namespace std;


int main(){

    const int N = 5000;

    {
        vector<double> A(N*N);

        srand(0);

        clock_t start = clock();
        for (int k=0;k<100;k++){
            for (int i=0;i<N;i++){
                for (int j=0;j<N;j++){
                    A[i*N+j] = rand();
                }
            }
        }

        cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;
    }

    {
        vector<vector<double> > A(N);
        for (int i=0;i<N;i++)
            A[i] = vector<double>(N);

        srand(0);

        clock_t start = clock();
        for (int k=0;k<100;k++){
            for (int i=0;i<N;i++){
                for (int j=0;j<N;j++){
                    A[i][j] = rand();
                }
            }
        }

        cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;
    }

    {
        double ** A = new double*[N];
        for (int i=0;i<N;i++)
            A[i] = new double[N];

        srand(0);

        clock_t start = clock();
        for (int k=0;k<100;k++){
            for (int i=0;i<N;i++){
                for (int j=0;j<N;j++){
                    A[i][j] = rand();
                }
            }
        }

        cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;
    }

    {
        double ** A = new double*[N];
        for (int i=0;i<N;i++) {
            A[i] = new double[N];
            memset(A[i], 0, sizeof(double) * N);
        }

        srand(0);

        clock_t start = clock();
        for (int k=0;k<100;k++){
            for (int i=0;i<N;i++){
                for (int j=0;j<N;j++){
                    A[i][j] = rand();
                }
            }
        }

        cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;
    }

    {
        double * A = new double[N * N];

        srand(0);

        clock_t start = clock();
        for (int k=0;k<100;k++){
            for (int i=0;i<N;i++){
                for (int j=0;j<N;j++){
                    A[i*N + j] = rand();
                }
            }
        }

        cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;
    }

    {
        double * A = new double[N * N];
        memset(A, 0, sizeof(double) * N * N);

        srand(0);

        clock_t start = clock();
        for (int k=0;k<100;k++){
            for (int i=0;i<N;i++){
                for (int j=0;j<N;j++){
                    A[i*N + j] = rand();
                }
            }
        }

        cout << "T="<< (clock()-start)/(double)(CLOCKS_PER_SEC/1000)<< "ms " << endl;
    }
}

这是问题所在: 我已经尝试了你和sonystarmap的解决方案。我直接将它复制到我的Visual Studio中。构建它。运行可执行文件。我的C++结果为83000毫秒,而Matlab结果为38秒(38000毫秒)。我不知道为什么? - Serdar Oztetik
2
你能提供一下你的项目设置吗?我开始觉得你在没有任何优化的情况下编译调试模式。 - Jose Palma
这是我构建代码的屏幕截图。我复制了你的代码并将其从debug更改为release,然后进行了构建。然后前往.exe文件所在的文件夹并运行它。这就是我所做的,我不知道还要做什么。你说过要使用优化编译,但我不知道如何操作。 https://www.dropbox.com/s/hoxffuo3yeuabwe/Untitled.png?dl=0 - Serdar Oztetik
1
我对VS不够了解,我们需要编译器的参数,也许这在项目属性下或其他地方可以找到? - Thomas

0
#include <vector>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>

int main() {
  const int N = 5000;
  std::vector<int> A(N*N);
  srand(0);
  clock_t start = clock();
  for(int k = 0; k < 100; ++k){
    for(int i = 0; i < N * N; ++i) {
        A[i] = rand();
    }
  }
  std::cout << (clock()-start)/(double)(CLOCKS_PER_SEC/1000) << "ms" << "\n";
  return 0;
}

在我的工作站上,编译器没有任何优化标志的情况下,运行时间从25-27秒缩短到了21秒。

-O3 -g -Wall -ftree-vectorizer-verbose=5 -msse -msse2 -msse3 -march=native -mtune=native -ffast-math


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接