在 C++ 中使用 OpenMP 并行化递归函数
Posted
技术标签:
【中文标题】在 C++ 中使用 OpenMP 并行化递归函数【英文标题】:Parallelizing recursive function using OpenMP in C++ 【发布时间】:2016-05-24 02:02:18 【问题描述】:我有以下递归程序,我想使用 OpenMP 对其进行并行化:
#include <iostream>
#include <cmath>
#include <numeric>
#include <vector>
#include <algorithm>
#include <thread>
#include <omp.h>
// Determines if a point of dimension point.size() is within the sphere
bool isPointWithinSphere(std::vector<int> point, const double &radius)
// Since we know that the sphere is centered at the origin, we can simply
// find the euclidean distance (square root of the sum of squares) and check to
// see if it is less than or equal to the length of the radius
//square each element inside the point vector
std::transform(point.begin(), point.end(), point.begin(), [](auto &x)return std::pow(x,2););
//find the square root of the sum of squares and check if it is less than or equal to the radius
return std::sqrt(std::accumulate(point.begin(), point.end(), 0, std::plus<int>())) <= radius;
// Counts the number of lattice points inside the sphere( all points (x1 .... xn) such that xi is an integer )
// The algorithm: If the radius is a floating point value, first find the floor of the radius and cast it to
// an integer. For example, if the radius is 2.43 then the only integer points we must check are those between
// -2 and 2. We generate these points by simulating n - nested loops using recursion and passing each point
// in to the boolean function isPointWithinSphere(...), if the function returns true, we add one to the count
// (we have found a lattice point on the sphere).
int countLatticePoints(std::vector<int> point, const double radius, const int dimension, int count = 0)
const int R = static_cast<int>(std::floor(radius));
#pragma omp parallel for
for(int i = -R; i <= R; i++)
point.push_back(i);
if(point.size() == dimension)
if(isPointWithinSphere(point, radius)) count++;
else count = countLatticePoints(point, radius, dimension, count);
point.pop_back();
return count;
int main(int argc, char ** argv)
std::vector<int> vec;
#pragma omp parallel
std::cout << countLatticePoints(vec, 5, 7) << std::endl;
return 0;
我尝试在主函数中添加一个并行区域,并在countLatticePoints
中并行化 for 循环,但我发现并行化与顺序运行算法几乎没有任何改进。
对于我可以使用的其他 OpenMP 策略,我们将不胜感激任何帮助/建议。
【问题讨论】:
【参考方案1】:我会采取建议路线。在尝试使用线程使您的程序更快之前,您首先要使其在单线程情况下更快。您可以进行几项改进。您正在制作大量点向量的副本,这会导致大量昂贵的内存分配。
将point
传递给isPointWithinSphere
作为参考。然后,而不是两个循环,使用一个循环来平方并累加point
中的每个元素。然后,在检查半径时,比较距离的平方而不是距离。这避免了sqrt
调用并将其替换为一个简单的正方形。
countLatticePoints
也应该引用point
。不要调用point.size()
,而是在每次递归时从dimension
中减去1,然后只检查dimension == 1
而不是计算大小。
尽管如此,如果您仍然想要/需要引入线程,则由于通过引用传递点,您需要进行一些调整。 countLatticePoint
需要有两个变体,一个是包含 OpenMP 指令的初始调用,另一个是没有它们的递归调用。
main
中的 #pragma omp parallel
不会做任何事情,因为只有一个代码块要执行。
【讨论】:
以上是关于在 C++ 中使用 OpenMP 并行化递归函数的主要内容,如果未能解决你的问题,请参考以下文章
使用 OpenMP 在 C、C++ 中并行化嵌套 for 循环的几种方法之间的区别