If the tree is very large spawning that many tasks could cause problems completely exhausting the entire thread pool causing performance problems elsewhere, this is because there is no dependency between the nodes and their parents so all will attempt to run concurrently. What I would do is have your Tree<T>
class implement IEnumerable<T>
that will return it's own Data
property and all it's children's Data
properties then use Parallel.ForEach
static void Traverse<T>(Tree<T> node, Action<T> action)
{
Parallel.ForEach(node, action);
}
//Elsewhere
class Tree<T> : IEnumerable<T>
{
Tree<T> Left { get; set; }
Tree<T> Right { get; set; }
T Data { get; set; }
public IEnumerator<T> GetEnumerator()
{
yield return this.Data;
if (Left != null)
{
foreach (var left in Left)
{
yield return left.Data;
}
}
if (Right != null)
{
foreach (var right in Right)
{
yield return right.Data;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
The only "Gotcha" you need to concern yourself with is if there are any closed loops in the tree where a child could be the parent of a higher level node which would cause infinite recursion.
EDIT: Here is a new version that does not use recursion on the GetEnumerator
and instead uses a Stack<Tree<T>>
object to hold the state so if you had extremely tall trees you can't have a StackOverflowException
. Also if you remove the comments from the commented lines it will stop the "infinite recursion" problem that the previous version had. But if you know you won't have any looping structures it is not necessary, so I left it commented out.
class Tree<T> : IEnumerable<T>
{
Tree<T> Left { get; set; }
Tree<T> Right { get; set; }
T Data { get; set; }
public IEnumerator<T> GetEnumerator()
{
Stack<Tree<T>> items = new Stack<Tree<T>>();
//HashSet<Tree<T>> recursiveCheck = new HashSet<Tree<T>>();
items.Push(this);
//recursiveCheck.Add(this);
while (items.Count > 0)
{
var current = items.Pop();
yield return current.Data;
if (current.Left != null)
//if(recursiveCheck.Add(current.Left))
items.Push(current.Left);
if (current.Right != null)
//if (recursiveCheck.Add(current.Right))
items.Push(current.Right);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}