如何使用 Open MP 并行化 A* 算法?

时间:2021-01-14 21:15:37

标签: c++ c++11 parallel-processing openmp

我在并行化 A* 算法时遇到问题。我曾尝试将单个 for 循环并行化,但这并没有改善任何东西。实际上串行实现仍然比这个快。你能帮我改进这个或给我一些想法吗?

while(openSet.size() > 0){
    PAIR current = {};
    int maxVal = INT32_MAX;

    int i;
    #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(openSet, maxVal, current, fScores)
    for(i = 0;i < openSet.size();i++){
        if(fScores[openSet[i].x * dim + openSet[i].y] < maxVal){
            #pragma omp ordered
            maxVal = fScores[openSet[i].x * dim + openSet[i].y];
            current = openSet[i];
        }
    }

    if(current.x == xEnd && current.y == yEnd){
        elapsed = omp_get_wtime() - start;
        //printMat(gScores, dim);
        printPath("res.txt", mat, cameFrom, current, dim, tc);
        break;
    }

    int rm = check_remove(openSet, current, tc);
    openSet.erase(openSet.begin() + rm);

    vector<PAIR> neighbours;

    if(current.x - 1 >= 0 && mat[(current.x - 1) * dim + current.y] != '1'){
        neighbours.push_back(PAIR(current.x - 1, current.y));
    }
    if (current.y - 1 >= 0 && mat[current.x * dim + (current.y - 1)] != '1'){
        neighbours.push_back(PAIR(current.x, current.y - 1));
    }
    if (current.x + 1 < dim && mat[(current.x + 1) * dim + current.y] != '1'){
        neighbours.push_back(PAIR(current.x + 1, current.y));
    }
    if (current.y + 1 < dim && mat[current.x * dim + (current.y + 1)] != '1'){
        neighbours.push_back(PAIR(current.x, current.y + 1));
    }
    
    int tentative_gScore;
    #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(neighbours, openSet, gScores, fScores, tentative_gScore)
    for(i = 0;i < neighbours.size();i++){
        tentative_gScore = gScores[current.x * dim + current.y] + 1;

        if(tentative_gScore < gScores[neighbours[i].x * dim + neighbours[i].y]){
            #pragma omp ordered
            cameFrom[neighbours[i].x * dim + neighbours[i].y] = current;
            gScores[neighbours[i].x * dim + neighbours[i].y] = tentative_gScore;
            fScores[neighbours[i].x * dim + neighbours[i].y] = tentative_gScore + hScore(); //(p.x, p.y, xEnd, yEnd)
            if(contains(openSet, neighbours[i]) == false){
                openSet.push_back(neighbours[i]);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

在第一个循环中,ordered 子句会导致大量时间浪费,如果您只需要 reduction,您可以使用 maxVal 来避免这种浪费。但是,由于您还需要 current,因此您必须手动进行缩减。因此,与其直接查找 maxValcurrent,不如为这些变量创建中间向量,即 maxValVectorcurrentVector。然后,我建议每个线程查找 maxValVector[omp_get_thread_num()]currentVector[omp_get_thread_num()]。因此,您不需要使用 ordered 子句并且每个线程都知道遇到的最大值。然后,您查看,对所涉及的线程数使用串行迷你循环,从 maxValcurrent 获取 maxValVectorcurrentVector。这应该能让您对第一个循环进行更有效的并行化。

在第二个循环中,变量 tentative_gScore 应该是私有的,以保证线程安全。此外,我也不认为这里需要 ordered 子句。不确定 openSet.push_back(neighbours[i]); 是怎么回事,但如果可能的话,这行应该由 atomiccritical 子句保护。

相关问题