为啥 OpenMP 不并行化 vtk IntersectWithLine 代码
Posted
技术标签:
【中文标题】为啥 OpenMP 不并行化 vtk IntersectWithLine 代码【英文标题】:Why does OpenMP not parallelize vtk IntersectWithLine code为什么 OpenMP 不并行化 vtk IntersectWithLine 代码 【发布时间】:2017-08-09 11:36:58 【问题描述】:如果在循环内执行 Vtk 代码,我很难理解为什么与 OpenMP 并行的 for-loop 不会使用所有 n_threads
线程 (=2x #cores)。具体来说,我想将线/射线与网格相交。我关注了this tutorial
-
从网格构建 OBB 树
将所有需要的线与网格相交
因为我想并行化它,所以我创建了n_threads
树,这样每个线程都可以使用它自己的树实例:
// Pre-allocate the array
int n_threads = omp_get_max_threads();
trees = std::vector<vtkSmartPointer<vtkOBBTree>>((unsigned int) n_threads);
// Build n_threads OBB trees
#pragma omp parallel for num_threads(n_threads)
for (int t = 0; t < n_threads; ++t)
trees[t] = vtkSmartPointer<vtkOBBTree>::New();
vtkSmartPointer<vtkPolyData> mesh_clone = vtkSmartPointer<vtkPolyData>::New();
#pragma omp critical (build_mesh_tree)
mesh_clone->DeepCopy(mesh);
trees[t]->SetDataSet(mesh_clone);
trees[t]->BuildLocator();
然后我遍历所有点来计算origin
和points
中每个点的交集
#pragma omp parallel for num_threads(n_threads)
for (unsigned long i = 0; i < n_points; ++i)
vtkSmartPointer<vtkPoints> intersection_points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkIdList> cell_ids = vtkSmartPointer<vtkIdList>::New();
int this_thread = omp_get_thread_num();
int code = trees[this_thread]->IntersectWithLine(
origin.data(), // pointer to the raw data
points.at(i).data(), // buffer of a Eigen matrix
intersection_points,
cell_ids);
// Do something with intersection_points and cell_ids
OpenMP 对于简单的 C++ 代码已经证明可以正常工作。然而,当包裹 Vtk 调用时,它并没有达到它的目的。我想这是因为 Vtk 已经提供了parallelization framework (ref. to the guide)。
如果是这样,您能否解释一下,为什么 OpenMP 无法并行运行与 vtk 相关的代码?如果不是,可能是什么原因?
【问题讨论】:
【参考方案1】:它究竟是如何失败的?你试过吗?打印线程号以查看是否生成了 n_threads?如果您“只是”在intersection_points
和cell_ids
中得到错误结果,那是因为这些数组在每个线程进入IntersectWithLine
函数时都会被重置(您可以查看实现here,第800 行-808)。
为了解决这个问题,想到的最简单的解决方案是让每个线程都有自己的列表,然后在关键部分将它们连接起来,但更快的方法可能是为每个线程预先分配这些列表的数组,然后读取结果,例如:
vtkSmartPointer<vtkPoints> *inter_points = new vtkSmartPointer<vtkPoints> [n_threads];
vtkSmartPointer<vtkIdList> *inter_cells = new vtkSmartPointer<vtkIdList> [n_threads];
for (unsigned long i = 0; i < n_threads; ++i)
inter_points[i] = vtkSmartPointer<vtkPoints>::New();
inter_cells[i] = vtkSmartPointer<vtkIdList>::New();
#pragma omp parallel for num_threads(n_threads)
for (unsigned long i = 0; i < n_points; ++i)
int this_thread = omp_get_thread_num();
int code = trees[this_thread]->IntersectWithLine(
origin.data(), // pointer to the raw data
points.at(i).data(), // buffer of a Eigen matrix
inter_points[this_thread],
inter_cells[this_thread);
// now concatenate the results to one array if necessarry
(没有编译,可能有语法错误,只是普通的 C,所以不是最安全的方法...)
【讨论】:
感谢您的回复!我在上面更新了我的问题。当然,覆盖intersection_points
和intersection_cells
的内容(可能线程不安全)是没有意义的。我现在将这段代码移到循环中。我也不清楚 OpenMP 如何失败。计算是正确的。它只是不会同时在所有线程上执行代码的 vtk 部分。我可以确认n_threads
已生成。似乎首先调用 vtk 函数的线程锁定了其他线程。以上是关于为啥 OpenMP 不并行化 vtk IntersectWithLine 代码的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 OpenMP 通过 C++ std::list 并行化 for 循环?