学习openmp-reduction

openmp-redcution使用场景

本文介绍openmp的reduction使用,reduction一般译为规约,与很多二分法中的合并操作。举一个最常见的例子,比如说你需要从一个整数数组中查找最小的数字,基于分治法的思想,把数组分为n个数组,分别找到每个数组中的最小值,得到n个最小值,最后从n个最小值中找到最小值即为整个数组的最小值。这就是openmp-reduction典型的使用场景,基于分治法的思想,将任务拆分为n个小任务,每个小任务分配线程并行执行,最后再将结果合并一起找到最终结果(规约)。所以reduction的使用场景一般包含以下两个特点的任务:

  • 任务拥有大量重复的处理操作,可以基于分治法拆分为小任务,多线程并行
  • 分别处理小任务后,需要对小任务结果进行合并处理。即最终的结果是依赖在全部数据、全部小任务的结果之上,并非各个小任务完全独立(如该这样直接使用parallel-for并行优化就可以)

例子

基于以上结论,reduction常见的使用例子有并行求和、并行求取最大最小值。openmp-reduction使用格式为

1
2
3
#pragma omp parallel for reduction(reduction合并操作:并行处理的数组)
for(...)
///...
  • reduction合并操作:原for循环中处理数组数据的具体操作,比如求和时为+,最大最小值则为max,min
  • 并行处理的数组:输入的并行处理的数组数据

并行求和

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 //没有reduction处理
    int sum = 0;
#pragma omp parallel for
    for(int i = 0; i < 10; ++i)
    {
        sum += i;
    }
    std::cout << "without reduction sum = " << sum << std::endl;
    sum = 0;
    //reduction
#pragma omp parallel for reduction(+:sum)
    for(int i = 0; i < 10; ++i)
    {
	 sum += i;
    }
    std::cout << "reduction sum = " << sum << std::endl;

最大最小值求取

1
2
3
4
5
6
7
8
9
//最大最小值
    int max_num = std::numeric_limits<int>::min();
    std::vector<int> vec = {1, 7, 2, 6, 4, 8, 0, 3};
#pragma omp parallel for reduction(max:max_num)
    for(int i = 0;  i < vec.size(); ++i)
    {
	max_num = std::max(max_num, vec[i]);
    }
    std::cout << "max number = "<< max_num << std::endl;

多个数组的reduction

openmp支持多个数组的同类型reduction,比如两个数组都需要求和时:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 int sum1 = 0;
    int sum2 = 0;
#pragma omp parallel for reduction(+:sum1, sum2)
    for(int i = 0; i < vec.size(); ++i)
    {
       sum1 += i;
       sum2 += vec[i];
    }
    std::cout << "sum1 = "<< sum1 << std::endl;
    std::cout << "sum2 = "<< sum2 << std::endl;

但并不支持,多个数组多个reduction操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

    //多变量reduction,openmp仅支持单个归约操作符,以下例子包含+、min两种归约操作,编译不通过
    //可以支持多个归约变量使用同一个归约操作
    /*sum = 0;
    int min_num = std::numeric_limits<int>::max();
#pragma omp parallel for reduction(+:sum,min:min_num)
    for(int i = 0; i < vec.size(); ++i)
    {
        sum += vec[i];
	min_num = std::min(min_num, vec[i]);
    }
    std::cout << "sum = "<< sum << std::endl;
    std::cout << "min number = " << min_num << std::endl;
    */

本文练习代码已上传至github:https://github.com/mangosroom/learn-openmp/tree/main/reduction


本文由芒果浩明发布,转载请注明出处。 本文链接:https://blog.mangoeffect.net/parallel-programming/learn-openmp-reduction.html


微信公众号