我正在尝试使用OpenMP并行化Dijkstra的算法,但串行版本的运行速度提高了40倍。我可能会错过一个概念或做错事。我是并行和OpenMP的新手。你能帮忙吗?感谢。
long* prev; // array of pointers to preceding vertices
long* dist; // array of distances from the source to each vertex
long* visited; // visited vertices, 0 if not visited, 1 otherwise
long** vSetDistance; // distance between i and j
void dijkstraAlgorithm(
long * prev,
long * dist,
long * visited,
long ** vSetDistance)
{
int i, j, min;
// Initialization: set every distance to INFINITY until we discover a path
for (i = 1; i <= numVertices; i++)
{
prev[i] = -1;
visited[i] = 0;
dist[i] = INFINITY;
}
// The distance from the source to the source is defined to be zero
dist[sourceVertex] = 0;
{
for (j = 1; j <= numVertices; j++)
{
min = -1;
#pragma omp parallel default(none) private(i, j) \
shared(min, visited, dist, prev, vSetDistance, numVertices)
{
/* This loop corresponds to sending out the explorers walking the paths,
* where the step of picking "the vertex, v, with the shortest path to s"
* corresponds to an explorer arriving at an unexplored vertex */
#pragma omp for
for (i = 1; i <= numVertices; i++)
#pragma omp critical
{
if (!visited[i] && ((min == -1) || (dist[i] <= dist[min])))
min = i;
}
visited[min] = 1; // visited = true
// relaxation
#pragma omp for
for (i = 1; i <= numVertices; i++)
{
if (vSetDistance[min][i])
{
if ((dist[min] + vSetDistance[min][i]) < dist[i])
{
dist[i] = dist[min] + vSetDistance[min][i];
prev[i] = min;
}
}
}
}
}
}
}
答案 0 :(得分:1)
并行化并不总是获得更高性能的免费门票。我看到两件可能导致经济放缓的事情。
关键部分可能花费大量时间处理同步问题。我不完全熟悉在OpenMP中如何实现这些部分,但我的第一个猜测是他们使用互斥锁来锁定对该部分的访问。互斥锁的锁定/解锁并不是非常便宜,并且该操作比您想要执行的操作昂贵得多。另外,由于循环完全处于临界区,因此除了一个线程之外的所有线程都将等待临界区中的线程完成。从本质上讲,该循环仍将以串行方式完成,并增加了同步开销。
可能没有足够的顶点可以从并行化中受益。同样,启动线程不是免费的,并且开销可能远远大于获得的时间。随着顶点数量变小,这变得越来越明显。
我的猜测是,第一个问题是大多数减速发生的地方。缓解此问题的最简单方法是以串行方式执行此操作。其次,您可以尝试让每个线程仅在其自己的部分中找到最小值,并将它们与并行部分之后的串行进行比较。