[英]Why am I getting this output when parallelising my tree search?
I have a binary tree where each node is a 0 or a 1. Each path from root to leaf is a bit string.我有一个二叉树,其中每个节点都是 0 或 1。从根到叶的每条路径都是一个位串。 My code prints out all bit strings sequentially, and it works fine.
我的代码按顺序打印出所有位字符串,并且工作正常。 However, when I try to parallelise it, I am getting unexpected output.
但是,当我尝试并行化它时,我得到了意想不到的 output。
Class Node Class 节点
public class Node{
int value;
Node left, right;
int depth;
public Node(int v){
value = v;
left = right = null;
}
}
Sequential Version of Tree.java树的顺序版本.java
import java.util.*;
import java.util.concurrent.*;
public class Tree{
Node root;
int levels;
LinkedList<LinkedList<Integer>> all;
Tree(int v){
root = new Node(v);
levels = 1;
all = new LinkedList<LinkedList<Integer>>();
}
Tree(){
root = null;
levels = 0;
}
public static void main(String[] args){
Tree tree = new Tree(0);
populate(tree, tree.root, tree.levels);
int processors = Runtime.getRuntime().availableProcessors();
System.out.println("Available core: "+processors);
// ForkJoinPool pool = new ForkJoinPool(processors);
tree.printPaths(tree.root);
// LinkedList<Integer> path = new LinkedList<Integer>();
// PrintTask task = new PrintTask(tree.root, path, 0, tree.all);
// pool.invoke(task);
// for (int i=0; i < tree.all.size(); i++){
// System.out.println(tree.all.get(i));
// }
}
public static void populate(Tree t, Node n, int levels){
levels++;
if(levels >6){
n.left = null;
n.right = null;
}
else{
t.levels = levels;
n.left = new Node(0);
n.right = new Node(1);
populate(t, n.left, levels);
populate(t, n.right, levels);
}
}
public void printPaths(Node node)
{
LinkedList<Integer> path = new LinkedList<Integer>();
printPathsRecur(node, path, 0);
// System.out.println("Inside ForkJoin: "+pool.invoke(new PrintTask(node, path, 0)));
}
LinkedList<LinkedList<Integer>> printPathsRecur(Node node, LinkedList<Integer> path, int pathLen)
{
if (node == null)
return null;
// append this node to the path array
path.add(node.value);
path.set(pathLen, node.value);
pathLen++;
// it's a leaf, so print the path that led to here
if (node.left == null && node.right == null){
printArray(path, pathLen);
LinkedList<Integer> temp = new LinkedList<Integer>();
for (int i = 0; i < pathLen; i++){
temp.add(path.get(i));
}
all.add(temp);
}
else
{
printPathsRecur(node.left, path, pathLen);
printPathsRecur(node.right, path, pathLen);
}
return all;
}
// Utility function that prints out an array on a line.
void printArray(LinkedList<Integer> l, int len){
for (int i = 0; i < len; i++){
System.out.print(l.get(i) + " ");
}
System.out.println("");
}
}
This produces the expected output:这将产生预期的 output:
0 0 0 0 0 0
0 0 0 0 0 1
0 0 0 0 1 0
0 0 0 0 1 1
...
Then I parallelised Tree.java:然后我并行化 Tree.java:
import java.util.*;
import java.util.concurrent.*;
public class Tree{
Node root;
int levels;
LinkedList<LinkedList<Integer>> all;
Tree(int v){
root = new Node(v);
levels = 1;
all = new LinkedList<LinkedList<Integer>>();
}
Tree(){
root = null;
levels = 0;
}
public static void main(String[] args){
Tree tree = new Tree(0);
populate(tree, tree.root, tree.levels);
int processors = Runtime.getRuntime().availableProcessors();
System.out.println("Available core: "+processors);
ForkJoinPool pool = new ForkJoinPool(processors);
// tree.printPaths(tree.root);
LinkedList<Integer> path = new LinkedList<Integer>();
PrintTask task = new PrintTask(tree.root, path, 0, tree.all);
pool.invoke(task);
for (int i=0; i < tree.all.size(); i++){
System.out.println(tree.all.get(i));
}
}
public static void populate(Tree t, Node n, int levels){
levels++;
if(levels >6){
n.left = null;
n.right = null;
}
else{
t.levels = levels;
n.left = new Node(0);
n.right = new Node(1);
populate(t, n.left, levels);
populate(t, n.right, levels);
}
}
}
and added a task class:并添加了一个任务 class:
import java.util.concurrent.*;
import java.util.*;
class PrintTask extends RecursiveAction {
LinkedList<Integer> path = new LinkedList<Integer>();
Node node;
int pathLen;
LinkedList<LinkedList<Integer>> all = new LinkedList<LinkedList<Integer>>();
PrintTask(Node node, LinkedList<Integer> path, int pathLen, LinkedList<LinkedList<Integer>> all){
this.node = node;
this.path = path;
this.pathLen = pathLen;
this.all = all;
}
protected void compute(){
if (node == null){
return;
}
path.add(pathLen, node.value);
pathLen++;
if(node.left == null && node.right == null){
printArray(path, pathLen);
LinkedList<Integer> temp = new LinkedList<Integer>();
for (int i = 0; i < pathLen; i++){
temp.add(path.get(i));
}
all.add(temp);
}
else{
invokeAll(new PrintTask(node.left, path, pathLen, all), new PrintTask(node.right, path, pathLen, all));
}
}
void printArray(LinkedList<Integer> l, int len){
for (int i = 0; i < len; i++){
System.out.print(l.get(i) + " ");
}
System.out.println("");
}
}
And I get this output:我得到了这个 output:
Available core: 8
0 0 1 0 1 1 1 0 0
0 1 1 0 1 1 1 0 1
0 0 1 1 1 0 0
1 1 1 1 0 1
1 0 1 1 0 1 1 1 0 0 1 1 0 0 0 1 1 1 0 1
1 1 1 1 0
0 1
...
[0, 1, 1, 0, 1, 1]
[0, 1, 1, 0, 0, 0]
[0, 1, 1, 0, 0, 1]
[0, 1, 1, 1, 0, 0]
[0, 1, 1, 1, 0, 1]
[0, 1, 1, 1, 0, 1]
[0, 1, 1, 1, 0, 1]
[0, 1, 1, 1, 0, 1]
[0, 1, 1, 1, 1, 0]
[0, 1, 1, 1, 0, 0]
...
So, while dynamically printing the path, it seems very different from the expected output where each path was made of 6 bits.因此,在动态打印路径时,它似乎与预期的 output 非常不同,其中每个路径由 6 位组成。 In this version, I store all paths in a list of lists, and print the list at the end.
在这个版本中,我将所有路径存储在列表列表中,并在最后打印列表。 It contains some correct looking bit strings, but the problem is that it's not all of them.
它包含一些看起来正确的位串,但问题是它不是全部。 It only outputs bit strings that start with 011.
它只输出以 011 开头的位串。
The issue with parallel implementation is due to the below line of code.并行实现的问题是由于下面的代码行。
invokeAll(new PrintTask(node.left, path, pathLen, all), new PrintTask(node.right, path, pathLen, all));
invokeAll
will execute the tasks in parallel. invokeAll
将并行执行任务。 This will result in 2 issues.这将导致2个问题。
path
and pathLen
variables that are shared across all the tasks.path
和pathLen
变量中。 Simplest option to correct it is to invoke left and right task in sequence.纠正它的最简单选项是依次调用左右任务。 Like below:
如下所示:
new PrintTask(node.left, path, pathLen, all).invoke();
new PrintTask(node.right, path, pathLen, all).invoke();
But doing so, you loose the benefits of parallel processing and it is as good as executing them sequentially.但是这样做,您失去了并行处理的好处,它与按顺序执行它们一样好。
To ensure correctness and have parallelism, will make the below changes为确保正确性和并行性,将进行以下更改
all
from LinkedList<LinkedList>
to LinkedList[]
.all
的类型从LinkedList<LinkedList>
更改为LinkedList[]
。 We will set the size of the array to 2 ^ (levels - 1)
to accommodate all the nodes in the tree.2 ^ (levels - 1)
以容纳树中的所有节点。insertIndex
variable, so that the leaf nodes will insert the list at the correct index in the result array.insertIndex
变量,以便叶节点将列表插入结果数组中正确的索引处。 We will left shift this insertIndex
at each level and for right tree, we will also increment it by 1.insertIndex
,对于右树,我们也将它增加 1。 Modified PrintTask:修改后的打印任务:
class PrintTask extends RecursiveAction {
LinkedList<Integer> path;
Node node;
LinkedList[] all;
int insertIndex;
PrintTask(Node node, LinkedList<Integer> path, LinkedList[] all, int insertIndex) {
this.node = node;
this.path = path;
this.all = all;
this.insertIndex = insertIndex;
}
protected void compute() {
if (node == null)
return;
path.add(node.value);
if (node.left == null && node.right == null)
all[insertIndex] = path;
else
invokeAll(new PrintTask(node.left, new LinkedList<>(path), all, insertIndex << 1),
new PrintTask(node.right, new LinkedList<>(path), all, (insertIndex << 1) + 1));
}
}
main()
changes: main()
更改:
...
LinkedList[] result = new LinkedList[1 << tree.levels - 1];
PrintTask task = new PrintTask(tree.root, path, result, 0);
pool.invoke(task);
for (LinkedList linkedList : result)
System.out.println(linkedList);
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.