OpenMP(二) for collapse reduction的用法

1,346 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

for和collapse

在for循环前,加上

#pragma omp parallel for

编译器就会自动为每个线程分配对应的工作量。

当遇到多重循环时, 一个parallel for只能并行最外面一层的循环。这时我们可以使用collapse对循环进行合并

假设有如下三重循环

#pragma omp parallel for
for(int i=0; i<M; i++) {
	for(int j=0;j<N;j++) {
		for(int k=0; k<P; k++){
			c[i][k] += a[i][k] * b[j][k]
		}
	}
}

只能并行最外层的一层循环,等用三行制导语句才能并行三重循环

#pragma omp parallel for
for(int i=0; i<M; i++) {
	#pragma omp parallel for
	for(int j=0;j<N;j++) {
		#pragma omp parallel for
		for(int k=0; k<P; k++){
			c[i][k] += a[i][k] * b[j][k]
		}
	}
}

我们也可以用collapse来合并循环

#pragma omp parallel for collapse(3) shared(a, b, c, M, N, P) private(j)
for(int i=0; i<M; i++) {
	for(int j=0;j<N;j++) {
		for(int k=0; k<P; k++){
			c[i][k] += a[i][k] * b[j][k]
		}
	}
}
private
#include <omp.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  int a=0, b=1;

  #pragma omp parallel private(a, b)
  {
    a++;
    b++;
    printf("threads=%d, a=%d, b=%d\n", omp_get_thread_num(), a, b);
  }
  printf("a=%d, b=%d\n", a, b);
  return 0;
}

运行结果

threads=6, a=1, b=4199858
threads=0, a=1, b=1
threads=3, a=1, b=4199858
threads=5, a=1, b=4199858
threads=4, a=1, b=4199858
threads=2, a=1, b=4199858
threads=1, a=1, b=16284705
threads=7, a=1, b=4199858
a=0, b=1

如果将private改为firstprivate,那么结果将是

threads=6, a=1, b=2
threads=0, a=1, b=2
threads=5, a=1, b=2
threads=2, a=1, b=2
threads=1, a=1, b=2
threads=3, a=1, b=2
threads=7, a=1, b=2
threads=4, a=1, b=2
a=0, b=1
reduction操作

omp支持的规约操作有 加减乘除、&&、||、max、min、&(按位与)、|(按位或)、^(按位XOR)

reduction过程:

  1. reduction默认参数列表是私有的,所以每个进程会初始化一个副本
  2. 每个线程更具设计的代码不断更新参数的值
  3. 并行区域结束时,会将每个进程得到的参数放在一起进行规约(例如求最大最小求和等)
  4. 将规约后的参数列表带出并行区域
#include <omp.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  int a=100;

  #pragma omp parallel for reduction(+:a)
    for (int i=0; i<10; i++){
      a += i;
      printf("thread=%d, a=%d\n", omp_get_thread_num(), a);
    }
  printf("a=%d\n", a);
  return 0;
}

运行结果:

thread=3, a=5
thread=2, a=4
thread=5, a=7
thread=1, a=2
thread=1, a=5
thread=0, a=0
thread=0, a=1
thread=4, a=6
thread=7, a=9
thread=6, a=8
a=145