首页 > 其他分享 >OpenMP 归约和reduction子句

OpenMP 归约和reduction子句

时间:2023-06-07 11:45:49浏览次数:36  
标签:myRank 变量 int sum reduction 归约 OpenMP

简述归约
  归约操作在MPI里也学过,不过那时候还不太熟悉这种操作。当时只知道MPI_Reduce可以把全局求和和集合通信封装起来,非常方便。实际上将相同的二元归约操作符重复地应用到一个序列上得到结果的计算过程都可以称为归约。

  python里那个难理解的reduce()函数也就是归约:

1 >>> from functools import reduce
2 >>> def myfun(x,y):
3 ...     return x+y-1
4 ... 
5 >>> reduce(myfun,[1,2,3])
6 4
7 >>> 

reduction子句
  OpenMP中的归约是parallel并行指令的reduction子句,在子句中指定归约操作符和归约变量。

  归约操作符是序列中的两两元素做的运算,一定是一个二元运算符。归约变量则保存归约操作的中间结果。OpenMP用归约变量为每个线程创建一个私有的变量,用来存储自己归约的结果,所以归约的代码不需要critical保护也不会发生冲突:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<omp.h>
 4 
 5 int main(int argc,char *argv[])
 6 {
 7     int sum=20;
 8     int thrdCnt=strtol(argv[1],NULL,10);
 9     //归约子句(归约操作符:归约变量)
10 #   pragma omp parallel num_threads(thrdCnt) reduction(+:sum)
11     {
12         int myRank=omp_get_thread_num();
13         sum+=myRank;
14         printf("%d->%d\n",myRank,sum);
15     }
16     printf("sum=%d\n",sum);//归约结果
17     return 0;
18 }

输出

 1 [lzh@hostlzh OpenMP]$ !gcc
 2 gcc -fopenmp -o test1.o test1.c
 3 [lzh@hostlzh OpenMP]$ ./test1.o 10
 4 9->9
 5 1->1
 6 2->2
 7 3->3
 8 4->4
 9 7->7
10 8->8
11 5->5
12 0->0
13 6->6
14 sum=65
15 [lzh@hostlzh OpenMP]$

可以看到在加法归约时,为每个线程创建的私有变量初始值是0,即使是0号线程也不例外。最后再把各自归约后的私有变量归约到归约变量上。

比较特殊的是,在减法时私有变量的初始值也是0,最后再把这些值按加法运算归约到归约变量上。这是因为减法不满足结合率,A-B-C-D-E-F和(A-B)-(C-D)-(E-F)是截然不同的。

除法运算也不满足结合率,但OpenMP的归约运算不包括除法运算。

虽然浮点数可以作归约,但如果对精度有要求,可能需要注意浮点数不满足结合率。

当进行乘法归约时,私有变量的初始值就是1了:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<omp.h>
 4 
 5 int main(int argc,char *argv[])
 6 {
 7     int sum=-2;
 8     int thrdCnt=strtol(argv[1],NULL,10);
 9     //归约子句(归约操作符:归约变量)
10 #   pragma omp parallel num_threads(thrdCnt) reduction(*:sum)
11     {
12         int myRank=omp_get_thread_num();
13         if(myRank!=0)
14             sum*=myRank;
15         printf("%d->%d\n",myRank,sum);
16     }
17     printf("sum=%d\n",sum);//归约结果
18     return 0;
19 }

输出

1 [lzh@hostlzh OpenMP]$ !gcc
2 gcc -fopenmp -o test1.o test1.c
3 [lzh@hostlzh OpenMP]$ ./test1.o 4
4 3->3
5 1->1
6 2->2
7 0->1
8 sum=-12
9 [lzh@hostlzh OpenMP]$

归约使用限制

允许使用的归约操作符

  只有+,*,-,&,|,^,&&,||八种。

对归约变量的操作

  在reduction子句修饰的并行块中,在书写逻辑上只允许对归约变量做如下的写入操作(之所以说是书写逻辑上,因为实际操作的始终是私有变量):

1 x = x op expr
2 x = expr op x (除了减法)   
3 x binop = expr
4 x++
5 ++x
6 x--
7 --x

  在并行块中对归约变量(实际上是对私有变量)做这些操作往往使用的是归约本身的操作符,如果使用其它操作符,只要满足上面的条件就是允许的,不过最后各个线程得到的结果仍然会按reduction子句指定的归约操作符所应当的归约方式(如+和-即做加法,*即做乘法)进行归约,而不会真的按照在并行块中表面上对归约变量的操作去执行:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<omp.h>
 4 
 5 int main(int argc,char *argv[])
 6 {
 7     int sum=-2;
 8     int thrdCnt=strtol(argv[1],NULL,10);
 9     //归约子句(归约操作符:归约变量)
10 #   pragma omp parallel num_threads(thrdCnt) reduction(*:sum)
11     {
12         int myRank=omp_get_thread_num();
13         if(myRank!=0)
14             sum*=myRank;
15         sum++;//实际是加在私有变量上!
16         printf("%d->%d\n",myRank,sum);
17     }
18     printf("sum=%d\n",sum);//归约结果
19     return 0;
20 }

输出

1 [lzh@hostlzh OpenMP]$ !gcc
2 gcc -fopenmp -o test1.o test1.c
3 [lzh@hostlzh OpenMP]$ ./test1.o 4
4 3->4
5 1->2
6 2->3
7 0->2
8 sum=-96
9 [lzh@hostlzh OpenMP]$

  这个-96来自(1*3+1)*(1*1+1)*(1*2+1)*(1+1)*(-2),总之理解好OpenMP归约的本质是在并行块里按归约操作符来生成指定初始值的私有变量,在并行块中看似对归约变量的操作是对私有变量的操作,最终再将各个线程计算好的私有变量按归约操作符的形式以特定的方式归约。

  特别注意最后的归约时’-‘操作符做加操作!下面这个例子能再次证明这一点:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<omp.h>
 4 
 5 int main(int argc,char *argv[])
 6 {
 7     int sum=30;
 8     int thrdCnt=strtol(argv[1],NULL,10);
 9     //归约子句(归约操作符:归约变量)
10 #   pragma omp parallel num_threads(thrdCnt) reduction(-:sum)
11     {
12         int myRank=omp_get_thread_num();
13         sum+=2;
14         printf("%d->%d\n",myRank,sum);
15     }
16     printf("sum=%d\n",sum);//归约结果
17     return 0;
18 }

输出

1 [lzh@hostlzh OpenMP]$ !gcc
2 gcc -fopenmp -o test1.o test1.c
3 [lzh@hostlzh OpenMP]$ ./test1.o 4
4 3->2
5 1->2
6 2->2
7 0->2
8 sum=38
9 [lzh@hostlzh OpenMP]$

 

标签:myRank,变量,int,sum,reduction,归约,OpenMP
From: https://www.cnblogs.com/ybqjymy/p/17462919.html

相关文章

  • OpenMP 传统形式的方阵向量并行乘法
    按行分配思路和MPI基本类似,不过OpenMP是共享内存的,不必做分发和聚集,申请的矩阵空间就不必是完全连续的。1#include<stdio.h>2#include<omp.h>3#include<stdlib.h>45#defineN400//规模(方针的阶数)6inti,j;//通用游标7double**mat=NULL;//矩阵对象......
  • HPL测试的配置(依赖于BLAS),通过OpenMpi进行实现
    1.1虚拟机的配置1.1.1Linux光盘映像文件由于对于Ubuntu系统更为熟悉,所以选择了最新版的Ubuntu系统作为Linux发行版。1.1.2Hypervisor由于之前一直使用VMware,对其中操作熟悉,因此选择VMware作为Hypervisor1.2搭建集群并安装相关程序1.2.1创建虚拟机以上为虚拟......
  • Number Reduction
    NumberReduction题意删除k位数,让原本的数变得最小(不含前导零)思路看官方题解学会的。记录每种数字出现的位置,原本有n位,那结果就有n-k位,一位位枚举,然后尽量放小的数,除了第一位不能放0,其他有0就放0。为什么vector可以用得这么6啊代码voidsolve(){ stringx; cin>>x; ci......
  • Fine-Grained学习笔记(5):(min+)卷积及背包问题的复杂度归约理论
    (min,+)卷积问题:给定$a_0,\cdots,a_{n-1},b_0,\cdots,b_{n-1}$,计算$c_k=min_i(a_i+b_{k-i})$全局决定性问题版本:给定$a_0,\cdots,a_{n-1},b_0,\cdots,b_{n-1}$,$c_0,\cdots,c_{2n-2}$,对于所有$k$,判断是否$\existsi,a_i+b_{k-i}<c_k$单解问题版本:给定$a_0,\cdots,a_......
  • Fine-Grained学习笔记(4):条件下界与归约,图论问题的复杂度归约理论
    和P与NP问题一样,Fine-Grained领域中的许多问题也能相互归约,这意味着当这些问题中的任意一个问题的复杂度下界得到了证明或证伪,那么一系列问题的复杂度下界就都能够得到解决.APSP猜想:不存在$O(|V|^{3-\delta})$时间的(对于任意实数边权图都有效的)(确定性的)APSP算法.APSP猜......
  • Stochastic Training of Graph Convolutional Networks with Variance Reduction
    目录概符号说明Motivation本文方法代码ChenJ.,ZhuJ.andSongL.Stochastictrainingofgraphconvolutionalnetworkswithvariancereduction.ICML,2018.概我们都知道,GCN虽然形式简单,但是对于结点个数非常多的情形是不易操作的:多层的卷积之后基本上每个结点......
  • 一小类矩阵乘法相关归约
    今天(2023.3.7)上午大聪明LgxTpre问我区间reverse全局kth怎么做,我以为他问的是区间reverse区间kth,确认了一下问题才发现他降智了区间reverse根本不会改全局kth......
  • OpenMP task construct 实现原理以及源码分析
    OpenMPtaskconstruct实现原理以及源码分析前言在本篇文章当中主要给大家介绍在OpenMP当中task的实现原理,以及他调用的相关的库函数的具体实现。在本篇文章当中最......
  • C++代码并行优化心得(OpenMP & TBB & Thread Pool)
    待更!  cmake引入OpenMP使用cmake中find_package指令查找openmp,格式如下:find_package(OpenMPREQUIRED)cmaketarget_link_libraries链接openmp:target_link_......
  • OpenMP Sections Construct 实现原理以及源码分析
    OpenMPSectionsConstruct实现原理以及源码分析前言在本篇文章当中主要给大家介绍OpenMP当中主要给大家介绍OpenMP当中sectionsconstruct的实现原理以及他调用......