我在并行化 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]);
}
}
}
}
答案 0 :(得分:1)
在第一个循环中,ordered
子句会导致大量时间浪费,如果您只需要 reduction
,您可以使用 maxVal
来避免这种浪费。但是,由于您还需要 current
,因此您必须手动进行缩减。因此,与其直接查找 maxVal
和 current
,不如为这些变量创建中间向量,即 maxValVector
和 currentVector
。然后,我建议每个线程查找 maxValVector[omp_get_thread_num()]
和 currentVector[omp_get_thread_num()]
。因此,您不需要使用 ordered
子句并且每个线程都知道遇到的最大值。然后,您查看,对所涉及的线程数使用串行迷你循环,从 maxVal
和 current
获取 maxValVector
和 currentVector
。这应该能让您对第一个循环进行更有效的并行化。
在第二个循环中,变量 tentative_gScore
应该是私有的,以保证线程安全。此外,我也不认为这里需要 ordered
子句。不确定 openSet.push_back(neighbours[i]);
是怎么回事,但如果可能的话,这行应该由 atomic
或 critical
子句保护。