嵌套循环中未正确忽略内部循环的 Pragma omp parallel
Posted
技术标签:
【中文标题】嵌套循环中未正确忽略内部循环的 Pragma omp parallel【英文标题】:Pragma omp parallel for inside inner loop is not correctly ignored in nested loop 【发布时间】:2020-08-08 07:33:18 【问题描述】:我正在尝试实现以下代码,以了解如何通过嵌套循环管理 OpenMP 线程,其中每个内部/外部循环在函数及其调用者中单独实现。
每个循环都是用语句实现的
#pragma omp parallel for
,我假设内部循环的 pragma
被忽略。
为了看到这一点,我在每个循环中打印了线程号。
然后,我可以看到以下内容,其中内部循环中的线程 id 始终为零,与调用者对应的线程号不同。为什么会这样?
Calling 0 from 0
Calling 2 from 1
Calling 6 from 4
Calling 8 from 6
Calling 4 from 2
Calling 7 from 5
Calling 5 from 3
Calling 0 from 0 // Expecting 3
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 0 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 0 from 0
Calling 0 from 0
Calling 0 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 9 from 7
Calling 1 from 0 // Expecting 7
Calling 2 from 0
Calling 3 from 0
Calling 0 from 0
Calling 3 from 1
Calling 0 from 0 // Expecting 1
Calling 1 from 0
Calling 2 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 3 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 0 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 0 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
Calling 1 from 0
Calling 0 from 0
Calling 1 from 0
Calling 2 from 0
Calling 3 from 0
#include <vector>
#include <omp.h>
#include <iostream>
#include <cstdio>
#include <limits>
#include <cstdint>
#include <cinttypes>
using namespace std;
const size_t kM = 4;
struct Mat
int elem[kM];
Mat(const Mat& copy)
for (size_t i = 0; i<kM; ++i)
this->elem[i] = copy.elem[i];
Mat()
for (size_t i = 0; i<kM; ++i)
elem[i] = 0;
void do_mat(Mat& m)
#pragma omp parallel for
for (int i = 0; i<kM; ++i)
printf(" \tCalling %d from %d\n", i, omp_get_thread_num());
elem[i] += m.elem[i];
;
int main ()
const int kN = 10;
vector<Mat> matrices(kN);
Mat m;
#pragma omp parallel for
for (int i = 0; i < kN; i++)
int tid = omp_get_thread_num();
printf("Calling %d from %d\n", i, tid);
matrices[i].do_mat(m);
return 0;
【问题讨论】:
【参考方案1】:我不确定我是否理解您的预期,但您得到的结果完全符合预期。
默认情况下,OpenMP 嵌套并行性被禁用,这意味着任何嵌套的 parallel
区域将创建与遇到它们的外部级别的线程一样多的 1 个线程组。
在您的情况下,您最外层的 parallel
区域创建了一个由 8 个线程组成的团队。这些中的每一个都将到达最里面的parallel
区域,并创建一个二级 1 线程团队。这些二级线程中的每一个,在其自己的团队中,排名为 0,因此您拥有打印的 0。
使用 g++ 9.3.0 编译的相同代码,通过设置 2 个环境变量 OMP_NUM_THREADS
和 OMP_NESTED
,我得到以下信息:
OMP_NUM_THREADS="2,3" OMP_NESTED=true ./a.out
Calling 0 from 0
Calling 5 from 1
Calling 0 from 0
Calling 1 from 0
Calling 2 from 1
Calling 0 from 0
Calling 1 from 0
Calling 3 from 2
Calling 3 from 2
Calling 2 from 1
Calling 6 from 1
Calling 1 from 0
Calling 0 from 0
Calling 1 from 0
Calling 3 from 2
Calling 2 from 1
Calling 2 from 0
Calling 0 from 0
Calling 1 from 0
Calling 2 from 1
Calling 3 from 2
Calling 0 from 0
Calling 1 from 0
Calling 3 from 2
Calling 2 from 1
Calling 3 from 0
Calling 7 from 1
Calling 0 from 0
Calling 3 from 2
Calling 2 from 1
Calling 3 from 2
Calling 0 from 0
Calling 1 from 0
Calling 1 from 0
Calling 2 from 1
Calling 4 from 0
Calling 8 from 1
Calling 0 from 0
Calling 3 from 2
Calling 2 from 1
Calling 2 from 1
Calling 0 from 0
Calling 1 from 0
Calling 3 from 2
Calling 1 from 0
Calling 9 from 1
Calling 2 from 1
Calling 0 from 0
Calling 1 from 0
Calling 3 from 2
也许这更符合您的预期?
【讨论】:
内循环中出现的数字是什么意思?在我的例子中,一切都显示为 0。但是,我们有 8 个线程(编号 0 - 7)并行执行的外部循环。我怀疑内部循环是否由编号为 0 的同一线程处理。 可能你的误解来自omp_thread_num()
返回的是最近遇到的队伍(最里面的)的线程id,不一定是第一个。因此,您看到的 0 与此完全一致,因为所有线程都是二级并行区域上的主线程,有 8 个不同的团队,每个团队有 1 个线程。在我的版本中,我们得到了 2 个二级团队,每个团队创建了 3 个线程。这就是为什么你会看到 ids 从 0 到 2 的原因。现在有意义吗?
啊,我明白了。感谢您的评论。当我删除了内部循环的 pragma 语句时,我的期望就来了。这是否意味着在内部/外部循环中使用omp parallel for
语句(没有任何特定选项)在内循环中会产生额外的开销?【参考方案2】:
除非您为 OpenMP 提供特殊选项,否则它会尝试在编译时拆分工作,并且很难使用嵌套并行性,因此它甚至不会尝试。
您可以参考this *** question 获取建议(例如,在 OpenMP 3.0+ 中使用collapse
)
【讨论】:
以上是关于嵌套循环中未正确忽略内部循环的 Pragma omp parallel的主要内容,如果未能解决你的问题,请参考以下文章