openmp:即使有深度限制,递归任务也比顺序慢

时间:2014-01-31 14:03:39

标签: c++ openmp

我有一个非常大的二叉树,我想在其上进行某些昂贵的计算。我想使用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() << "s\n";

    return 0;
}

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

我做错了吗?你知道如何改进这段代码吗?谢谢!

1 个答案:

答案 0 :(得分:3)

某些任务实际上不可并行化,因为某些资源一次只能由一个线程访问(线程安全)。这就是动态记忆的情况。

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

=&GT;将在每个malloc / free周围执行锁定。

所以,你不能轻易改进这种代码。