我正在实现一个DFS来查找迷宫的退出,目前它是单线程的。
我打算通过使用相同的单线程算法创建几个搜索树的线程来提高效率,但是当我遇到交叉点时,我正在随机化哪个方向。
例如,线程遇到一个交叉点,它们可以向东或向西。其中一半去东方,一半去西方。这将继续,直到其中一个线程找到解决方案路径。
这是以并行方式实现DFS的有效方式吗?
答案 0 :(得分:2)
如果使用Java进行递归并行工作,请使用Java 7中引入的Fork和Join API。
public class MazeNode {
// This class represents a Path from the start of your maze to a certain node. It can be a) a dead end, b) the exit, c) have child Paths
...
}
public class MazeTask extends RecursiveTask<MazeNode>
{
private MazeNode node;
MazeTask(MazeNode node) {
this.node = node;
}
// Returns null or the exit node
@Override
protected MazeNode compute() {
if (node.isDeadEnd())
return null;
else if (node.isExit())
return node;
else { // node has ways to go
// implement as many directions as you want
MazeTask left = new MazeTask(node.getLeft());
MazeTask right = new MazeTask(node.getRight());
left.fork(); // calculate in parallel
MazeNode rightNode = right.compute(); // calculate last Task directly to save threads
MazeNode leftNode = left.join(); // Wait for the other task to complete and get result
if (rightNode != null)
return rightNode;
else
return leftNode; // This assumes there is only one path to exit
}
}
public static void main(String[] args) {
MazeNode maze = ...
MazeNode exit = new ForkJoinPool().invoke(new MazeTask(maze));
}
答案 1 :(得分:0)
[UPDATE1]
以下是我的线程同步建议(但基于我们与@IraBaxter的讨论,我不再确定我的方式会带来任何好处):
当算法启动时,只需要一个线程,直到你得到第一个fork。当这一个线程到达那里时,它应该将所有可能的结果(左,右,中)放入堆栈并停止自身。然后,由于堆栈中存在一些元素,因此激活多个线程以从存储在堆栈中的边开始。当这些线程中的每一个到达一个分支时,所有结果都被放入堆栈并且线程自己停止(不是一次全部停止,每个都在需要时)并从堆栈中获取边缘。等等。每当任何线程被停止时(无论是因为fork还是死胡同),它都会切换到等待堆栈边缘的模式(如果堆栈不为空则取一个)。并且每次向堆栈添加一些边缘时,都会通知线程堆栈的非空虚。
我使用了术语&#34; edge&#34;这里的意思是fork的位置加上方向从给定的fork开始。 Stack为您提供算法的深度优先属性。
PS:可以通过减少同步点的数量来优化这种方法。我们可以在每个线程的单独工作清单中收集分叉边缘,并且不要停止该线程直到它到达死胡同。我们从这个工作清单中排除了这个线程决定在每个fork上运行的边缘。然后,当线程到达死端时,我们将本地工作列表迁移到全局工作列表。因此,空闲线程使用同步从全局工作列表中的点开始。