【问题标题】:parallel multiply matrix openmp is slower than sequential并行乘法矩阵openmp比顺序矩阵慢
【发布时间】:2017-08-14 06:44:46
【问题描述】:

我是一名新的 OpenMp 程序员,现在我遇到了将两个矩阵相乘的问题。这是我的并行代码,但没有我预期的那么快。 例如,我给它一个 3000 * 3000 矩阵和 3000 * 3000 并且我的 Domain 是 2(随机数是 0 或 1 )并且并行比顺序慢

    clock_t tStart = clock();
    cout<<(char)169<<" parallel "<<(char)170<<endl;
    int a,b,c,Domain ;
    cin>>a>>b>>c>>Domain;
    srand(time(0));
    int **arr1;
    int **arr2;
    int **arrRet;

    arr1 = new int*[a];
    #pragma omp for schedule (dynamic)
    for(int i=0 ; i<a ; i++)
    arr1[i] = new int [b];

    arr2 = new int*[b];
    #pragma omp for schedule (dynamic)
    for(int i=0 ; i<b ; i++)
    arr2[i] = new int [c];

    arrRet = new int*[a];
    #pragma omp for schedule (dynamic)
    for(int i=0 ; i<a ; i++)
    arrRet[i] = new int [c];

    #pragma omp for schedule (dynamic)
    for(int i=0 ; i<a ; i++)
    {
        #pragma omp for schedule (dynamic)
        for(int j=0; j<b ; j++)
        {
        arr1[i][j]=rand()%Domain;
        }
    }

    //cout<<"\n\n\n";
    #pragma omp for schedule (dynamic)
    for(int i=0 ; i<b ; i++)
    {
        #pragma omp for schedule (dynamic)
        for(int j=0 ; j<c ; j++)
        {
        arr2[i][j]=rand()%Domain;
        }
    }

    //cout<<"\n\n\n";
    #pragma omp for schedule (dynamic)
    for(int i=0 ; i<a ; i++)
        #pragma omp for schedule (dynamic)
        for(int j2=0 ; j2<c ; j2++)
        {
            int sum=0;
            #pragma omp parallel for shared(sum) reduction(+:sum)
            for(int j=0 ; j<b ; j++)
            {
                sum+=arr1[i][j]*arr2[j][j2];
            }
            arrRet[i][j2]=sum;
        }
    printf("Time taken : %.4fs\n", (double)(clock() - tStart) / CLOCKS_PER_SEC);

【问题讨论】:

  • 不要自己做矩阵乘法。这太疯狂了。矩阵乘法是本书中最古老的问题。获取一些库来为您执行此操作,例如 OpenBLAS。还可以使用Armadillo 来保存您的矩阵。停止保留这些蹩脚的数组来保存矩阵。它们很慢,因为您的编译器不能vectorize 它们。您可以将 Armadillo 与 OpenBLAS 链接,它会为您和您的处理器功能进行并行化,从而为您提供最佳性能。
  • @TheQuantumPhysicist 我的老师告诉我我不能使用图书馆:(
  • 好的。然后使用std::vector,不要使用多维数组。使用一维数组并创建一个访问器函数,该函数将访问一维数组中的元素 (i,j)。这样你就可以让一切变得最快。还要记住,更多的线程并不意味着更快的结果。从 1 个线程开始,不断增加数量并研究速度与内核数量的关系,并尝试了解结果。

标签: c++ parallel-processing openmp


【解决方案1】:

有许多高度优化的linear algebra libraries 可以免费使用。我强烈建议您尽可能使用其中之一。

您的性能下降可能是由多种原因造成的。以下列表详细说明了一些最常见的原因:

  • 当每次迭代的工作量完全平衡时使用schedule(dynamic)。省略子句会将调度设置为static,这更适合这种类型的并行化。

  • 内存分配压力过大。您实际上不需要为单个矩阵保留多个内存区域。由于程序中的矩阵大小不会改变,因此您可以完美地为每个矩阵使用单个分配。这也提高了数据的局部性,因为连续的行在内存中彼此靠近。然后,您可以使用A[ i * b + j ] 访问每个元素,其中b 是列数。

int *A = (int *) malloc( a * b * sizeof(int) );
  • 在您的代码中,您似乎错过了parallel 区域。这导致除了最后一个之外的所有omp for,都没有被多个线程执行。

  • 使用 collapse(2) 在嵌套循环中合并您的 omp for 构造,如下例所示:

#pragma omp for collapse(2)
for( i = 0; i < a; i++ ) {
   for( j = 0; j < b; j++ ) {
      // your parallel code
   }
}

【讨论】:

    猜你喜欢
    • 2014-05-03
    • 2013-05-18
    • 2017-09-14
    • 2018-08-24
    • 2018-11-29
    • 2018-12-05
    • 2020-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多