当我尝试使用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);
}
答案 0 :(得分:1)
正如已提到的user2357112,您的罪魁祸首是printf
(以及rand()
)。这些函数可以访问进程的全局状态并通过互斥锁保护它(通常)。因此,在时间关键的并行循环中使用这些函数毫无意义,它们强制序列化您的执行。
在编写OMP程序时,您也可以减轻痛苦。您应该将所有声明为private
的变量作为使用它们的作用域中的局部变量。然后不需要额外的OMP注释。
答案 1 :(得分:0)
您的代码中存在数据争用,因为rand()
不是线程安全的函数。内部有一个具有状态的PRNG,因此在没有同步的情况下不能被多个线程调用。使用不同的PRNG(例如Xershift + of Mersenne Twister),每个线程使用一个生成器,不要忘记使用不同的种子值播种它们(小心time(NULL)
)。