C 如何正确使用OpenMP?
我正在建立一个程序,可以将两个矩阵相乘。问题是,我应该使用OpenMP并行化,但每次只使用一个“for”循环(首先是外部循环,然后是其子循环,然后是内部循环),对于每个并行化方法,我应该在使用不同数量的线程(1,2,4,8,16,32,64128)时分析结果 我的问题是,我应该将OpenMP并行/私有部分放在哪里,以及哪些变量应该是私有/共享的以实现这一点C 如何正确使用OpenMP?,c,linux,multithreading,openmp,matrix-multiplication,C,Linux,Multithreading,Openmp,Matrix Multiplication,我正在建立一个程序,可以将两个矩阵相乘。问题是,我应该使用OpenMP并行化,但每次只使用一个“for”循环(首先是外部循环,然后是其子循环,然后是内部循环),对于每个并行化方法,我应该在使用不同数量的线程(1,2,4,8,16,32,64128)时分析结果 我的问题是,我应该将OpenMP并行/私有部分放在哪里,以及哪些变量应该是私有/共享的以实现这一点 // code to be parallelized using n_threads omp_set_dynamic(0); //
// code to be parallelized using n_threads
omp_set_dynamic(0); // Explicitly disable dynamic teams
omp_set_num_threads(n_threads);
#pragma omp parallel for shared(a, b, c) private(i,j)
for (i=0; i < TAM_MATRIZ; i++){
for (j=0; j < TAM_MATRIZ; j++) {
c[i][j] = 0; // initialize the result matrix with zeros
for (k=0; k < TAM_MATRIZ; k++){
#pragma omp atomic
c[i][j] += a[i][k]*b[k][j];
}
}
printf("Number of threads used: %d\n", omp_get_num_threads());
}
//要使用n\u线程并行化的代码
omp_集_动态(0);//显式禁用动态团队
omp_集合_num_线程(n_线程);
#pragma omp并行用于共享(a,b,c)私有(i,j)
对于(i=0;i
编辑
实际上,它有三个程序,第一个程序只并行外部循环,第二个程序只并行中间循环,最后一个程序并行内部循环。
每个版本应该使用指定的线程(1,2,4,8,16,32,64128)运行8次,然后我们应该比较不同程序版本和使用不同线程号的相同版本的性能
我的疑问在于,应该在哪里共享或使私有it变为变量。并行第一个循环时,应该共享哪些变量?当我处理第二个循环时,共享哪些变量?等等
在我看来,我不能共享任何变量,因为我将有多个线程同时工作,并且可以产生部分结果,但我知道我错了,我在这里问的基本上是为了理解为什么。你的思路是正确的-这其实很简单
- 您在
子句中遗漏了private
——这将导致问题,因为在外部定义时,默认情况下是k
。最好的方法不是为每个变量显式地选择数据共享,而是尽可能在本地声明变量(例如,shared
,这几乎总是需要的,而且更容易推理。for(int…)
,a
,b
,来自外部,隐式c
-循环变量在内部声明,隐式共享
私有
<> L>>P>幸运的是,不需要<代码>α-PrimaOMP原子< /代码>。每个线程在不同的<代码> i>代码> -所以没有两个线程可以尝试更新相同的<代码> [i] [j] < /代码>。删除<代码>原子< /代码>将极大地提高性能。如果你需要原子,也可以考虑减少作为替代。
- 如果你想打印
,你应该在循环外,但在并行区域内打印。在你的情况下,这意味着你必须将omp\u get\u num\u threads
拆分为omp parallel for
和omp parallel
。使用omp for
确保只有一个线程输出omp single
collapse(2)
来并行化外层的2个循环。不要使用(并行)对于
两次,除非您完全知道自己在做什么。原因是并行化中间循环会产生更多较小的工作,从而增加相对开销
在您的特定情况下,可以安全地假设TAM_MATRIZ>>n_线程
0,这意味着最外层的循环具有足够的并行功,可以有效地使用所有线程
重申数据共享规则。适用于正常的并行
区域
- 在
区域的词法范围内定义的变量(和并行循环变量)是隐式私有的。这些是线程处理的变量。如果变量仅在词法范围内使用,则始终1在最窄的词法范围内定义它并行
- 默认情况下,词法范围外定义的变量是隐式共享的。这些变量通常是并行区域的输入/输出-因此必须共享。请确保避免数据争用
私有
/共享
数据共享属性2
0否则在此处使用OpenMP甚至没有意义
例外情况适用于不昂贵C++类型的不平凡C++类型。
<代码> < <代码> >代码>第一私密< /代码>有助于显式使用。
< P>您应该考虑交换<代码> J<代码>代码> <代码> K<代码>循环>这样的memset(c, 0, sizeof(c[0][0])*TAM_MATRIZ*TAM_MATRIZ);
#pragma omp parallel for
for (int i=0; i < TAM_MATRIZ; i++)
for (int k=0; k < TAM_MATRIZ; k++)
for (int j=0; j < TAM_MATRIZ; j++)
c[i][j] += a[i][k]*b[k][j];
memset(c,0,sizeof(c[0][0])*TAM_MATRIZ*TAM_MATRIZ);
#pragma-omp并行
对于(int i=0;i
这可能比并行化有更多的性能优势,因为它可以更好地利用缓存。但它还有一个更微妙的额外优势:它删除了求和上的依赖链
浮点数学不是关联的,这意味着(a+b)+c不一定等于a+(b+c)。当你的内循环经过k
时,每次迭代都会写入同一个变量c[i][j]
。如果你改变求和的顺序(例如使用SIMD),你可能会得到不同的结果