高性能计算-openmp编程-(探究 for/collapse)(11)

1. 目标:探究嵌套循环 for 和 collapse 编程

2. 内容

(1). for 并行区默认对最近外层的循环控制变量私有,并对其划分并行,不必指明 private,内层循环体入口的循环控制变量声明及或定义[ for (int i=0;)]默认私有;如果在并行区外声明或定义的内层循环控制变量默认 shared,应显式 pravate该变量,否则可能导致线程数据竞争,结果错误。如下代码,应注意:

a. 使用collapse(3) ,C[r][c]的计算数据不同数据在不同线程之间,会造成数据竞争,计算错误;如果使用临界区,速度过慢。

// 并行计算矩阵相乘
void gemm_2(int* A,int* B,long* C,int N,int NT)
{
struct timeval start,end;
float time;
//串行计算代码
gettimeofday(&start,NULL); //开始时间
omp_set_num_threads(NT);
// 使用collapse(3) C[r][c] 的计算数据在不同进程之间,会造成数据竞争,需要原子操作,造成速度过慢。
// 使用collapse(3) for 默认循环指标变量私有,如果在循环外声明定义k,需要private(k)
#pragma omp parallel for collapse(2) schedule(guided) proc_bind(close)
for(int r=0;r<N;r++)//A 行遍历
{
for(int c=0;c<N;c++)//B 列遍历
{
#if 0 //临界区+collapse(3)
for(int k=0;k<N;k++)//A B K方向遍历
{
#pragma omp critical
C[r*N+c] += A[r*N+k] * B[k*N+c];
}
#else
long sum=0; //使用局部变量减少传入参数引用
for(int k=0;k<N;k++)//A B K方向遍历
sum += A[r*N+k] * B[k*N+c];
C[r*N+c] = sum;
#endif
}
}
gettimeofday(&end,NULL);
time = end.tv_sec-start.tv_sec+(end.tv_usec-start.tv_usec)/1e6;
printf("func %s N %d threads_num %d sum %ld useSec %f\n",__func__,N,NT,sum(C,N),time);
}

(2). collapse(n),最外n层的循环控制变量默认私有。在并行区内声明的变量默认 pravite。如下是一个 collapse(2) + collapse(2) + reduction 的示例:

a. 外两层循环步进为4,影响每个循环控制变量在每个线程中的起始值。内两层步进量内部循环。

//矩阵一维行列分块 A块 4*N,B块 N*4,并行,K在内层,collapse(2+2) + reduction
void gemm_8(int* A,int* B,long* C,int N,int NT)
{
struct timeval start,end;
float time;
int r,c,k;
//串行计算代码
gettimeofday(&start,NULL); //开始时间
omp_set_num_threads(NT);
#pragma omp parallel for collapse(2) private(r,c) schedule(guided) proc_bind(close)
for(r=0;r<N;r+=4)//A 行遍历
{
for(c=0;c<N;c+=4)//B 列遍历
{
#pragma omp parallel for collapse(2) schedule(guided) proc_bind(close)
for(int nr=0;nr<4;nr++) //A块内行遍历
{
for(int nc=0;nc<4;nc++) //B快内列遍历
{
long sum =0;
#pragma omp parallel for reduction(+:sum) schedule(guided) proc_bind(close)
for(int k=0;k<N;k++) //K方向遍历
sum += A[(r+nr)*N+k] * B[k*N+c+nc];
C[(r+nr)*N+c+nc] = sum;
}
}
}
}
gettimeofday(&end,NULL);
time = end.tv_sec-start.tv_sec+(end.tv_usec-start.tv_usec)/1e6;
printf("func %s N %d threads_num %d sum %ld useSec %f\n",__func__,N,NT,sum(C,N),time);
// print_matrix(C,N,N);
}
posted @   安洛8  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示