减少 OpenMP 并行中的迭代次数
Decreasing number of iterations in OpenMP parallel for
我在C++程序中有一个parallel for
,它必须循环到一定次数的迭代。每次迭代都会计算算法的可能解决方案,一旦找到有效的解决方案,我想退出循环(如果完成一些额外的迭代也可以)。我知道迭代次数应该从一开始就固定在parallel for
中,但由于我没有在以下代码中增加迭代次数,因此是否可以保证线程在继续当前迭代之前检查条件?
void fun()
{
int max_its = 100;
#pragma omp parallel for schedule(dynamic, 1)
for(int t = 0; t < max_its; ++t)
{
...
if(some condition)
max_its = t; // valid to make threads exit the for?
}
}
修改循环计数器适用于 OpenMP 工作共享结构的大多数实现,但该程序将不再符合 OpenMP,并且无法保证该程序可与其他编译器配合使用。
由于 OP 可以通过一些额外的迭代进行,因此取消 OpenMP 将是要走的路。 OpenMP 4.0 正是为此目的引入了"取消"结构。 它将请求终止工作共享构造并将线程传送到其末尾。
void fun()
{
int max_its = 100;
#pragma omp parallel for schedule(dynamic, 1)
for(int t = 0; t < max_its; ++t)
{
...
if(some condition) {
#pragma omp cancel for
}
#pragma omp cancellation point for
}
}
请注意,在性能方面可能会付出代价,但如果中止循环时整体性能更好,则可能需要接受这一点。
在 OpenMP4.0 之前的实现中,唯一符合 OpenMP 的解决方案是使用 if 语句尽快接近循环的常规结束,而无需执行实际的循环主体:
void fun()
{
int max_its = 100;
#pragma omp parallel for schedule(dynamic, 1)
for(int t = 0; t < max_its; ++t)
{
if(!some condition) {
... loop body ...
}
}
}
希望对您有所帮助!
干杯 -迈克尔
修改max_its
,因为标准说它必须是循环不变表达式。
但是,您可以做的是使用布尔共享变量作为标志:
void fun()
{
int max_its = 100;
bool found = false;
#pragma omp parallel for schedule(dynamic, 1) shared(found)
for(int t = 0; t < max_its; ++t)
{
if( ! found ) {
...
}
if(some condition) {
#pragma omp atomic
found = true; // valid to make threads exit the for?
}
}
}
这种逻辑也可以通过任务而不是工作共享构造来实现。代码的草图如下所示:
void algorithm(int t, bool& found) {
#pragma omp task shared(found)
{
if( !found ) {
// Do work
if ( /* conditionc*/ ) {
#pragma omp atomic
found = true
}
}
} // task
} // function
void fun()
{
int max_its = 100;
bool found = false;
#pragma omp parallel
{
#pragma omp single
{
for(int t = 0; t < max_its; ++t)
{
algorithm(t,found);
}
} // single
} // parallel
}
这个想法是单个线程创建max_its
任务。每个任务都将分配给一个等待线程。如果某些任务找到有效的解决方案,则所有其他任务都将通过找到的共享变量通知。
如果some_condition
是一个"始终有效"的逻辑表达式,那么你可以这样做:
for(int t = 0; t < max_its && !some_condition; ++t)
这样,很明显需要!some_condition
才能继续循环,并且无需阅读其余代码即可发现"如果some_condition
,循环结束"
否则(例如,如果some_condition
是循环内部某些计算的结果,并且将some_condition
"移动"到 for 循环条件很复杂,那么使用 break
显然是正确的做法。
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 迭代时从向量和内存中删除对象
- 如何在c++迭代器类型中包装std::chrono
- 带过滤器的现代迭代c++集合
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- C++矢量迭代
- 是否可以使用OpenMP并行化一个列表,该列表可以在每次迭代中添加新元素
- 我可以将映射迭代器与 OpenMP 并行使用吗?
- OpenMP STL设置容器迭代器
- 迭代器openMP的循环
- 限制为迭代器的 openmp
- OpenMP - 在每次循环迭代中启动一个新线程
- 减少 OpenMP 并行中的迭代次数
- 我可以用openmp迭代C++11 std::元组吗
- OpenMP嵌套的迭代次数不等
- OpenMP计算每个线程的循环迭代次数
- 并行区域的OpenMP迭代for循环
- 为什么人们在 OpenMP 循环之前声明迭代值