OpenMP:即使在深度极限的情况下,递归任务也比顺序慢

openmp: recursive task slower than sequential even with depth limit

本文关键字:任务 递归 顺序 情况下 极限 深度 OpenMP      更新时间:2023-10-16

我有一棵非常大的二进制树,我想在上进行某些昂贵的计算。我想使用openMP及其任务布拉格马并平行这些方法。

作为测试,我已经平行了freeTree功能,并且创建了一个大型示例测试树。为了防止产卵许多任务,我将创建任务的创建限制在树的前两个层面上。因此,有效地创建了4个任务。

以下是最小的工作示例:

#include <chrono>
#include <iostream>
class Node {
public:
    int data;
    Node* l;
    Node* r;
    Node(Node* left, Node* right) : l(left), r(right) {}
};
Node* createRandomTree(int depth) {
    if (depth == 0)
        return new Node(NULL, NULL);
    return new Node(createRandomTree(depth - 1), createRandomTree(depth - 1));
}
void freeTree(Node* tree) {
    if (tree == NULL) return;
    freeTree(tree->l);
    freeTree(tree->r);
    delete tree;
}
void freeTreePar(Node* tree, int n = 0) {
    if (tree == NULL) return;
    Node *l = tree->l, *r = tree->r;
    if (n < 2) {
        #pragma omp task
        freeTreePar(l, n + 1);
        #pragma omp task
        freeTreePar(r, n + 1);
    } else {
        freeTree(tree->l);
        freeTree(tree->r);
    }
    // taskwait is not necessary
    delete tree;
}
int main(int argc, char const *argv[])
{
    std::chrono::time_point<std::chrono::system_clock> start, end;
    Node* tree = createRandomTree(22);
    start = std::chrono::system_clock::now();
    #pragma omp parallel shared(tree)
    {
        #pragma omp single nowait
        freeTreePar(tree);
    }
    end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "finished computation at " << std::ctime(&end_time)
              << "elapsed time: " << elapsed_seconds.count() << "sn";
    return 0;
}

当我运行此代码时,大约需要 0.38 秒才能释放树。但是,如果我直接致电freeTree(root),则仅需 0.2 秒。因此,即使树非常大(2^22个元素),即使在此特定的测试用例中,任务的大小相等,我也无法使用并行方法获得性能提高。

我做错了什么吗?您知道我如何改进此代码吗?谢谢!

某些任务并不是真正可行的,因为某些资源只能一次通过一个线程访问(线程安全)。这就是动态内存的情况。

malloc/free现在主要是线程安全。

=>将在每个Malloc/Free周围执行一个锁。

因此,您无法轻易改进此类代码。