我使用gsl(GNU Scienctific Library)和open mp创建了一个简单的c程序。在这个简单的程序中,我想测试顺序和并行的执行时间。以下是程序片段 main.c 。
#include "omp.h"
#include <stdio.h>
#include <gsl/gsl_matrix.h>
#include <time.h>
int main()
{
omp_set_num_threads(4);
int n1=10000, n2=10000;
gsl_matrix *A = gsl_matrix_alloc(n1, n2);
int i,j;
struct timeval tv1, tv2, tv3, tv4;
gettimeofday(&tv1, 0);
for(i=0; i<n1; i++)
{
for(j=0; j<n2; j++)
{
gsl_matrix_set(A, i, j, i*j*1000000);
}
}
gettimeofday(&tv2, 0);
long elapsed = (tv2.tv_sec-tv1.tv_sec)*1000000 + tv2.tv_usec-tv1.tv_usec;
printf("Sequential Duration:%ldms\n", elapsed);
gettimeofday(&tv3, 0);
#pragma omp parallel for private(i,j)
for(i=0; i<n1; i++)
{
for(j=0; j<n2; j++)
{
gsl_matrix_set(A, i, j, i*j*1000000);
}
}
gettimeofday(&tv4, 0);
elapsed = (tv4.tv_sec-tv3.tv_sec)*1000000 + tv4.tv_usec-tv3.tv_usec;
printf(" Parallel Duration:%ldms\n", elapsed);
return 0;
}
然后我使用以下命令编译了上面的代码:
gcc -fopenmp main.c -o test -lgsl -lgslcblas -lm
以下是该计划的结果:
Sequential Duration:11980106ms
Parallel Duration:20624043ms
为什么,并行部分比顺序部分慢。我该如何优化此代码?感谢
答案 0 :(得分:3)
正如你所写的那样,j
变量在所有线程之间共享,因此线程会不断地覆盖其他线程状态,导致它们迭代它们已经覆盖的值。
尝试与openmp并行化时,应始终最小化变量的范围。将j的范围移动到循环中或明确标记为私有:
#pragma omp parallel for private(j)
时钟也会计算处理器时间而不是实时,您可能想要使用gettimeofday
你的矩阵太小而无法从并行化中获益,线程开销将占主导地位。将它增加到~10000x10000即可开始看到。
答案 1 :(得分:0)
这里的问题是你不知道程序gsl_matrix_set
对A做了什么。你不知道它是否是线程安全的。要更改该矩阵中的一个元素,您需要将整个矩阵提供给例程,而不是仅提供元素的索引。这通过虚假分享来嗅见(参见例如this answer)。
我会试试这个
gsl_matrix_set(A[i][j],i*j*1000000);
如果这不起作用,你感兴趣的只是串行和并行之间的时差我会做
A[i][j] = i*j*1000000
答案 2 :(得分:-1)
在线程部分,试试这个:
#pragma omp parallel private(i,j)
for(i=0; i<n1; i++)
{
for(j=0; j<n2; j++)
{
gsl_matrix_set(A, i, j, i*j*1000000);
}
}
或
#pragma omp parallel for
for(i=0; i<n1; i++)
{
for(j=0; j<n2; j++)
{
gsl_matrix_set(A, i, j, i*j*1000000);
}
}