使用OpenMP乘以矩阵比串行化方式花费更多时间

时间:2016-03-29 18:05:36

标签: c matrix parallel-processing openmp

当我尝试使用OpenMP乘以两个大方矩阵时,并行方式比序列方式花费更多时间。我做错了吗?

对具有4个内核(超线程)的机器进行简单测试,结果是并行计算大约100秒,串行计算大约10秒!

这是我的并行代码:

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MATSIZE 500
#define MAXRAND 100

int main (int argc, char *argv[]) 
{
    double startTime = 0.0, stopTime = 0.0;
    startTime = omp_get_wtime();

    int i, j, k;
    static int  a[MATSIZE][MATSIZE],b[MATSIZE][MATSIZE],c[MATSIZE][MATSIZE];

    srand(time(NULL));

    #pragma omp parallel shared(a,b,c) private(i,j,k)
    {
        #pragma omp for
        for (i=0; i<MATSIZE; i++)
            for (j=0; j<MATSIZE; j++){
                a[i][j]= rand()%MAXRAND;
                b[i][j]= rand()%MAXRAND;
                c[i][j]= 0;
            }
    }

    printf("Matrix A:\n");
    for (i=0; i<MATSIZE; i++){
        for (j=0; j<MATSIZE; j++) 
            printf("%d   ", a[i][j]);
        printf("\n"); 
    }
    printf("******************************************************\n");
    printf("Matrix B:\n");
    for (i=0; i<MATSIZE; i++){
        for (j=0; j<MATSIZE; j++) 
            printf("%d   ", b   [i][j]);
        printf("\n");
    }
    printf("******************************************************\n");

    #pragma omp parallel shared(a,b,c) private(i,j,k)
    {   
        #pragma omp for
        for (i=0; i<MATSIZE; i++){
            for(j=0; j<MATSIZE; j++)       
                for (k=0; k<MATSIZE; k++){
                    c[i][j] += a[i][k] * b[k][j];
                    printf(".");
                }
        }
    }

    printf("\nResult Matrix:\n");
    for (i=0; i<MATSIZE; i++){
        for (j=0; j<MATSIZE; j++) 
            printf("%d   ", c[i][j]);
        printf("\n"); 
    }
    stopTime = omp_get_wtime();
    printf("Elapsed time = %f \n", stopTime - startTime);
}

以下是序列号:

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MATSIZE 500
#define MAXRAND 100

int main (int argc, char *argv[]) 
{
    double startTime = 0.0, stopTime = 0.0;
    startTime = omp_get_wtime();

    int i, j, k;
    static int  a[MATSIZE][MATSIZE],b[MATSIZE][MATSIZE],c[MATSIZE][MATSIZE];

    srand(time(NULL));

    for (i=0; i<MATSIZE; i++)
        for (j=0; j<MATSIZE; j++){
            a[i][j]= rand()%MAXRAND;
            b[i][j]= rand()%MAXRAND;
            c[i][j]= 0;
        }

    printf("Matrix A:\n");
    for (i=0; i<MATSIZE; i++){
        for (j=0; j<MATSIZE; j++) 
            printf("%d   ", a[i][j]);
        printf("\n"); 
    }
    printf("******************************************************\n");
    printf("Matrix B:\n");
    for (i=0; i<MATSIZE; i++){
        for (j=0; j<MATSIZE; j++) 
            printf("%d   ", b   [i][j]);
        printf("\n");
    }
    printf("******************************************************\n");

    for (i=0; i<MATSIZE; i++){
        for(j=0; j<MATSIZE; j++)       
            for (k=0; k<MATSIZE; k++){
                c[j][i] += a[j][k] * b[k][i];
                printf(".");
            }
    }

    printf("\nResult Matrix:\n");
    for (i=0; i<MATSIZE; i++){
        for (j=0; j<MATSIZE; j++) 
            printf("%d   ", c[i][j]);
        printf("\n"); 
    }
    stopTime = omp_get_wtime();
    printf("Elapsed time = %f \n", stopTime - startTime);
}

2 个答案:

答案 0 :(得分:1)

正如已提到的user2357112,您的罪魁祸首是printf(以及rand())。这些函数可以访问进程的全局状态并通过互斥锁保护它(通常)。因此,在时间关键的并行循环中使用这些函数毫无意义,它们强制序列化您的执行。

在编写OMP程序时,您也可以减轻痛苦。您应该将所有声明为private的变量作为使用它们的作用域中的局部变量。然后不需要额外的OMP注释。

答案 1 :(得分:0)

您的代码中存在数据争用,因为rand()不是线程安全的函数。内部有一个具有状态的PRNG,因此在没有同步的情况下不能被多个线程调用。使用不同的PRNG(例如Xershift + of Mersenne Twister),每个线程使用一个生成器,不要忘记使用不同的种子值播种它们(小心time(NULL))。