OpenMP - 并行 For 循环
OpenMP - Parallel For Loop
我使用二维向量。我有两个操作:
- 使用 (i,j) 从向量中读取数据
使用(i,j)将项目添加到向量
我怎样才能并行化这段代码?如果我只添加 #pragma omp parallel for shared(tempVector, objVector)
,OpenMP 可以防止日期竞争吗?
vector < myObject > objVector;
vector< vector <int> > tempVector(4);
for(int i = 0; i < objVector.size(); i++) {
int x = objVector[i].X,
y = objVector[i].Y;
if(x <= Xmiddle+DIAMETER && y <= Ymiddle+DIAMETER)
{
tempVector[0].push_back(i);
}
if(x >= Xmiddle-DIAMETER && y <= Ymiddle+DIAMETER)
{
tempVector[1].push_back(i);
}
if(x <= Xmiddle+DIAMETER && y >= Ymiddle-DIAMETER)
{
tempVector[2].push_back(i);
}
if(x >= Xmiddle-DIAMETER && y >= Ymiddle-DIAMETER)
{
tempVector[3].push_back(i);
}
}
您需要使用#critical 指令才能正确访问共享变量:
#include <omp.h>
main()
{
int x;
x = 0;
#pragma omp parallel shared(x)
{
#pragma omp critical
x = x + 1;
} /* end of parallel section */
}
示例取自:https://computing.llnl.gov/tutorials/openMP/#CRITICAL
如果我是你,我会想一些不同的事情(不幸的是你不能在这种情况下使用#reduction,但你绝对可以重新调整代码以获得相同的结果)。
不幸的是,在这种情况下,OpenMP 无法阻止数据竞争。 shared 子句允许所有线程查看向量变量,但它不对它们的访问进行排序。 Vector 的 push_back 函数不是线程安全的,因为它可能导致重新分配(增长)vector 的底层存储。
此代码可以并行化,但它的可扩展性取决于您愿意投入多少实施工作。要确定适当的工作量,请确定这部分需要您整个工作量的时间应用。这里有两种(在许多可能的)方法来并行化您的问题:
- 性能稳定的低工作量 - 制作 tempVector 1D 和与 objVector 相同的大小。不是将带有索引列表的 4 个向量放入 objVector,而是将 tempVector[i] 设为 0-3 objVector[i] 的哪个 bin。这可以通过一个简单的 openmp parallel for 来完成。稍后使用 tempVector 时,获取特定 bin 的所有值将涉及扫描所有 tempVector。如果只有 4 个 bin,这实际上可能表现得很好。
- 更多努力和最佳可伸缩性 - 为每个线程提供它自己的本地 tempVector 并使用 openmp parallel for 跨 objVector 并行化。这样每个线程都可以使用 vector 的 push_back 函数,因为它们是唯一访问该 vector 的线程。将 tempVector 的所有本地副本合并到一个共享的 tempVector 中可以通过原子地添加大小然后批量复制片段来完成。
我使用二维向量。我有两个操作:
- 使用 (i,j) 从向量中读取数据
使用(i,j)将项目添加到向量 我怎样才能并行化这段代码?如果我只添加
#pragma omp parallel for shared(tempVector, objVector)
,OpenMP 可以防止日期竞争吗?vector < myObject > objVector; vector< vector <int> > tempVector(4); for(int i = 0; i < objVector.size(); i++) { int x = objVector[i].X, y = objVector[i].Y; if(x <= Xmiddle+DIAMETER && y <= Ymiddle+DIAMETER) { tempVector[0].push_back(i); } if(x >= Xmiddle-DIAMETER && y <= Ymiddle+DIAMETER) { tempVector[1].push_back(i); } if(x <= Xmiddle+DIAMETER && y >= Ymiddle-DIAMETER) { tempVector[2].push_back(i); } if(x >= Xmiddle-DIAMETER && y >= Ymiddle-DIAMETER) { tempVector[3].push_back(i); } }
您需要使用#critical 指令才能正确访问共享变量:
#include <omp.h>
main()
{
int x;
x = 0;
#pragma omp parallel shared(x)
{
#pragma omp critical
x = x + 1;
} /* end of parallel section */
}
示例取自:https://computing.llnl.gov/tutorials/openMP/#CRITICAL
如果我是你,我会想一些不同的事情(不幸的是你不能在这种情况下使用#reduction,但你绝对可以重新调整代码以获得相同的结果)。
不幸的是,在这种情况下,OpenMP 无法阻止数据竞争。 shared 子句允许所有线程查看向量变量,但它不对它们的访问进行排序。 Vector 的 push_back 函数不是线程安全的,因为它可能导致重新分配(增长)vector 的底层存储。
此代码可以并行化,但它的可扩展性取决于您愿意投入多少实施工作。要确定适当的工作量,请确定这部分需要您整个工作量的时间应用。这里有两种(在许多可能的)方法来并行化您的问题:
- 性能稳定的低工作量 - 制作 tempVector 1D 和与 objVector 相同的大小。不是将带有索引列表的 4 个向量放入 objVector,而是将 tempVector[i] 设为 0-3 objVector[i] 的哪个 bin。这可以通过一个简单的 openmp parallel for 来完成。稍后使用 tempVector 时,获取特定 bin 的所有值将涉及扫描所有 tempVector。如果只有 4 个 bin,这实际上可能表现得很好。
- 更多努力和最佳可伸缩性 - 为每个线程提供它自己的本地 tempVector 并使用 openmp parallel for 跨 objVector 并行化。这样每个线程都可以使用 vector 的 push_back 函数,因为它们是唯一访问该 vector 的线程。将 tempVector 的所有本地副本合并到一个共享的 tempVector 中可以通过原子地添加大小然后批量复制片段来完成。