简述归约

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

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

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

reduction子句

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

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

#include<stdio.h>
#include<stdlib.h>
#include<omp.h>int main(int argc,char *argv[])
{int sum=20;int thrdCnt=strtol(argv[1],NULL,10);//归约子句(归约操作符:归约变量)
#   pragma omp parallel num_threads(thrdCnt) reduction(+:sum){int myRank=omp_get_thread_num();sum+=myRank;printf("%d->%d\n",myRank,sum);}printf("sum=%d\n",sum);//归约结果return 0;
}

输出

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

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

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

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

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

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

#include<stdio.h>
#include<stdlib.h>
#include<omp.h>int main(int argc,char *argv[])
{int sum=-2;int thrdCnt=strtol(argv[1],NULL,10);//归约子句(归约操作符:归约变量)
#   pragma omp parallel num_threads(thrdCnt) reduction(*:sum){int myRank=omp_get_thread_num();if(myRank!=0)sum*=myRank;printf("%d->%d\n",myRank,sum);}printf("sum=%d\n",sum);//归约结果return 0;
}

输出

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

归约使用限制

允许使用的归约操作符

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

对归约变量的操作

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

x = x op expr
x = expr op x (除了减法)
x binop = expr
x++
++x
x--
--x

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

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

输出

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

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

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

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

输出

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

【OpenMP学习笔记】2:OpenMP中的归约和reduction子句相关推荐

  1. OPENMP学习笔记(1)——简介,模型,运行

    OPENMP学习笔记(1)--简介,模型,运行 简介: OpenMP的英文全称是Open Multiprocessing,一种应用程序接口(API,即Application Program Inter ...

  2. OpenMP学习笔记1

    OpenMP学习笔记1 介绍 在C/C++中,OpenMP可以通过使用预处理指令来让程序并行化.OpenMP指令使用的格式为: #pragma omp 指令 [子句[子句]-] fork/join并行 ...

  3. SpringBoot学习笔记(4)----SpringBoot中freemarker、thymeleaf的使用

    1. freemarker引擎的使用 如果你使用的是idea或者eclipse中安装了sts插件,那么在新建项目时就可以直接指定试图模板 如图: 勾选freeMarker,此时springboot项目 ...

  4. Hadoop学习笔记—11.MapReduce中的排序和分组

    Hadoop学习笔记-11.MapReduce中的排序和分组 一.写在之前的 1.1 回顾Map阶段四大步骤 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出 ...

  5. 【theano-windows】学习笔记十七——梯度中的consider_constant

    前言 主要是在写玻尔兹曼机相关的theano时, 在计算梯度grad的时候发现一个参数名字叫做consider_constant,来看看这个到底做了什么事情 参考博客: using consider_ ...

  6. 【theano-windows】学习笔记十一——theano中与神经网络相关函数

    前言 经过softmax和MLP的学习, 我们发现thenao.tensor中除了之前的博客[theano-windows]学习笔记五--theano中张量部分函数提到的张量的定义和基本运算外, 还有 ...

  7. 【theano-windows】学习笔记六——theano中的循环函数scan

    前言 Scan是Theano中最基础的循环函数, 官方教程主要是通过大量的例子来说明用法. 不过在学习的时候我比较习惯先看看用途, 然后是参数说明, 最后再是研究实例. 国际惯例, 参考网址 官网关于 ...

  8. SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理

    在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式. 1. 使用JdbcTemplate 在SpringBoot中提供了JdbcTemplate模板 ...

  9. cockroachdb mysql_CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储...

    CockroachDB学习笔记--[译]CockroachDB中的SQL:映射表中数据到键值存储 原文标题:SQL in CockroachDB: Mapping Table Data to Key- ...

最新文章

  1. 机器学习隐私研究新进展:数据增强风险被低估,新算法“降服”维数依赖
  2. 如何解析字符串类型的xml
  3. Linux生成ssh公钥免密码登录远程主机和Xshell跨跳板机登录
  4. java模块_Java 9 揭秘(2. 模块化系统)
  5. java数字分割的下划线_Java-数值中使用下划线进行分隔
  6. linux系统支持最大内存,「Linux」- 查找系统支持的最大内存 @20210225
  7. shiro身份验证失败捕获的异常对应信息
  8. 基于计算机视觉的葡萄检测分级系统
  9. 网络化智能型维修电工电气控制技能实训智能考核装置
  10. 国外苹果id_爆料者称苹果仍在继续研发iPhone屏下Touch ID
  11. POJ3580:SuperMemo
  12. HTML- 表单(简单易懂)
  13. Qt下图片加密的两种方式
  14. 改变指标改变图(FusionChart)
  15. 【PMP】核对单和核查表的区别
  16. 链栈的数据结构以及链栈的实现
  17. 工具技巧和读文档 | 读函数式编程接口文档 | 匿名内部类 | lambda表达式 |IDEA
  18. 北航计算机考博经验,北航考博经验总结和感受
  19. 产品经理经常面临的系统须知大拷问
  20. GCN笔记:Graph Convolution Neural Network,ChebNet

热门文章

  1. matlab的详细使用方法
  2. Xmind8破解教程
  3. ls路由算法_路由算法区分管理距离和最大跳数
  4. 大水题--健康的荷斯坦奶牛
  5. Java开源UML建模
  6. ffmepg AVFrame用法
  7. java数组求最大值
  8. 【尚硅谷前端html+css】02_css
  9. 金晓龙获批担任蚂蚁消金董事长,年内多家消费金融公司一把手换人
  10. CSS几种常见的文字动态效果