<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Parallel Programming with .NET : Parallelism Blockers</title><link>http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx</link><description>Tags: Parallelism Blockers</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Achieving Speedups with Small Parallel Loop Bodies</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/06/9703059.aspx</link><pubDate>Sat, 06 Jun 2009 23:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9703059</guid><dc:creator>toub</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9703059.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9703059</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9703059</wfw:comment><description>&lt;P&gt;The Parallel class represents a significant advancement in parallelizing managed loops.&amp;nbsp; For many common scenarios, it just works, resulting in terrific speedups.&amp;nbsp; However, while ideally Parallel.For could be all things to all people, such things rarely work out, and we’ve had to prioritize certain scenarios over others.&lt;/P&gt;
&lt;P&gt;One area Parallel.For may fall a bit short is in attempts to use it with very small loop bodies, such as:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;int [] array = new int[100000000]; &lt;BR&gt;Parallel.For(0, array.Length, i=&amp;gt; &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; array[i] = i*i*i; &lt;BR&gt;});&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Such an operation should be readily parallelizable; after all, every iteration is completely independent of every other iteration, and we’re dealing with a big data parallel problem.&amp;nbsp; The devil is in the details, however.&amp;nbsp; To handle typical scenarios where the time it takes to complete each iteration ends up being non-uniform, Parallel.For’s implementation takes a lot of care to load balance across all threads participating in the loop, and that load balancing comes at a small performance cost.&amp;nbsp; This cost is typically trumped by the performance benefits that come from doing the load balancing; however, when the body of the loop is as tiny as it is in the example above, even small overheads add up.&amp;nbsp; Another overhead that also contributes is the delegate invocation required to invoke the loop body.&amp;nbsp; It can be easy to forget when looking at a Parallel.For call that Parallel.For is really just a method, accepting as a parameter a delegate to be invoked for every iteration.&amp;nbsp; That invocation isn’t free, and in the above case may even be more expensive than the body of the loop itself.&lt;/P&gt;
&lt;P&gt;Fear not, however, as there exist ways to still achieve good speedups on such cases.&amp;nbsp; One way is based on creating larger chunks of work for Parallel to operate on: as the chunk size increases, the overhead costs start to pale in comparison, and speedups are realized.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Consider a new ForRange method you could implement:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public static ParallelLoopResult ForRange( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int fromInclusive, int toExclusive, Action&amp;lt;int, int&amp;gt; body);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Unlike For, which invokes the body once per iteration, ForRange will invoke the body with a start and end of a range.&amp;nbsp; Thus, given an initial sequential loop like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;for(int i=0; i&amp;lt;N; i++) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DoWork(i); &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;with For it would be parallelized by replacing the for loop with a Parallel.For:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Parallel.For(0, N, i=&amp;gt; &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DoWork(i); &lt;BR&gt;});&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;and with ForRange, it would be parallelized by &lt;EM&gt;wrapping&lt;/EM&gt; the for loop with a ForRange:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;ForRange(0, N, (from,to) =&amp;gt; &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(int i=from; i&amp;lt;to; i++) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DoWork(i); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;});&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;There are several ways we can now implement ForRange.&amp;nbsp; The first is simply by doing a little math.&amp;nbsp; We can calculate the boundaries of each range and use a Parallel.For to run the user-supplied body action for each range, e.g.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public static ParallelLoopResult ForRange( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int fromInclusive, int toExclusive, Action&amp;lt;int, int&amp;gt; body) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int numberOfRanges = Environment.ProcessorCount; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int range = toExclusive - fromInclusive; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int stride = range / numberOfRanges; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (range &amp;lt;= 0) numberOfRanges = 0; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Parallel.For(0, numberOfRanges, i =&amp;gt; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int start = i * stride; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int end = (i == numberOfRanges - 1) ? toExclusive : start + stride; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; body(start, end); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Another way is actually by using Parallel.ForEach under the covers.&amp;nbsp; Rather than doing the math as was done above, we can write an iterator in C# that yields the ranges, and then Parallel.ForEach over those ranges, e.g.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public static ParallelLoopResult ForRange( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int fromInclusive, int toExclusive, Action&amp;lt;int, int&amp;gt; body) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int rangeSize = (toExclusive - fromInclusive) / Environment.ProcessorCount; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rangeSize == 0) rangeSize = 1; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Parallel.ForEach( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CreateRanges(fromInclusive, toExclusive, rangeSize), range =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; body(range.Item1, range.Item2); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;private static IEnumerable&amp;lt;Tuple&amp;lt;int,int&amp;gt;&amp;gt; CreateRanges( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int fromInclusive, int toExclusive, int rangeSize) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Enumerate all of the ranges &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (int i = fromInclusive; i &amp;lt; toExclusive; i += rangeSize) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int from = i, to = i + rangeSize; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (to &amp;gt; toExclusive) to = toExclusive; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield return Tuple.Create(from, to); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;(You can download an implementation of ForRange as part of the Beta 1 samples at &lt;A title=http://code.msdn.microsoft.com/ParExtSamples href="http://code.msdn.microsoft.com/ParExtSamples" mce_href="http://code.msdn.microsoft.com/ParExtSamples"&gt;http://code.msdn.microsoft.com/ParExtSamples&lt;/A&gt;.)&lt;/P&gt;
&lt;P&gt;In general, we expect the design and implementation of Parallel.For will be right for the vast majority of scenarios.&amp;nbsp; However, solutions like those above can be used to accommodate cases that don’t quite fit the mold.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9703059" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Getting random numbers in a thread-safe way</title><link>http://blogs.msdn.com/pfxteam/archive/2009/02/19/9434171.aspx</link><pubDate>Thu, 19 Feb 2009 17:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9434171</guid><dc:creator>toub</dc:creator><slash:comments>24</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9434171.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9434171</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9434171</wfw:comment><description>&lt;P&gt;It’s very common in a parallel application to need random numbers for this or that operation.&amp;nbsp; For situations where random numbers don’t need to be cryptographically-strong, the System.Random class is typically a fast-enough mechanism for generating values that are good-enough.&amp;nbsp; However, effectively utilizing Random in a parallel app can be challenging in a high-performance manner.&lt;/P&gt;
&lt;P&gt;There are several common mistakes I’ve seen developers make.&amp;nbsp; The first is to assume that Random is thread-safe and is ok to be used concurrently from multiple threads.&amp;nbsp; This is a bad idea, and can have some drastic consequences on the quality of the random numbers (degrading them well below the “good enough” bar).&amp;nbsp; For an example of this, consider the following program:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;using System; &lt;BR&gt;using System.Threading; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;class Program &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; static void Main(string[] args) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Random rand = new Random(); &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Parallel.For(0, 1000000, (i, loop) =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rand.Next() == 0) loop.Stop(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (true) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(rand.Next()); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.ReadLine(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;While it won’t happen every time you run the app, on a multi-core machine it’s likely that once the Parallel.For in this example exits, rand.Next() will always return 0.&amp;nbsp; Not very random, is it?&amp;nbsp; This is due to an implementation detail of Random that does not tolerate multithreaded access (it wasn’t designed for it, and the docs explicitly call out that Random should not be used from multiple threads, as they do for most types in the .NET Framework).&lt;/P&gt;
&lt;P&gt;Another common mistake is to fix a problem like that in the previous example by instantiating a new Random instance each time a random number is needed.&amp;nbsp; This can also affect the quality of the random numbers.&amp;nbsp; When a seed isn’t explicitly provided to Random through its constructor, it internally uses Environment.TickCount (at least in the current release) as the seed.&amp;nbsp; TickCount returns a value that’s heavily influenced by the resolution of the system timer, and thus multiple calls to TickCount in a row are likely to yield the same value (on the system on which I’m writing this post, TickCount changes in value approximately once every 15 milliseconds).&amp;nbsp; This means that Random will suffer a similar fate, as is exemplified in the following program:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;using System; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;class Program &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; static void Main(string[] args) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int lastNumber = 0, count = 0; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (true) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Get the next number &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int curNumber = new Random().Next(); &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // If it's the same as the previous number,&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // &lt;/FONT&gt;&lt;FONT face=Consolas&gt;note the increased count &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (curNumber == lastNumber) count++; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Otherwise, we have a different number than &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // the previous. Write out the previous number &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // and its count, then start &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // over with the new number. &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (count &amp;gt; 0) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count + ": " + lastNumber); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lastNumber = curNumber; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count = 1; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This program continually creates new Random instances and gets a random value from each, counting the number of “random” values in a row that are the same.&amp;nbsp; When I run this app, I consistently see each number showing up thousands of times before the number changes; again, not very random.&amp;nbsp; The point of this example is that, in a multithreaded context, you may be creating a Random instance for each iteration, but many iterations across threads are likely to end up with the same value.&lt;/P&gt;
&lt;P&gt;There are several approaches then one could take in using Random from multiple threads to avoid these kinds of issues.&lt;/P&gt;
&lt;P&gt;One approach is to use a lock.&amp;nbsp; A shared Random instance is created, and every access to the Random instance is protected by a lock, e.g.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;public static class RandomGen1 &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static Random _inst = new Random(); &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static int Next() &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock (_inst) return _inst.Next(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This has the benefit of being easy to write, simple to explain, and obviously does the right thing.&amp;nbsp; Unfortunately, there’s an expensive lock on every access, and the more threads that want random numbers, the more contention there will be for this lock.&amp;nbsp; Sharing hurts.&lt;/P&gt;
&lt;P&gt;Another approach is to use one Random instance per thread, rather than one per AppDomain (as is the case with the RandomGen1 approach shown above).&amp;nbsp; Here’s one way that might be implemented:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=consolas&gt;public static class RandomGen2 &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static Random _global = new Random(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ThreadStatic] &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static Random _local; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static int Next() &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Random inst = _local; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (inst == null) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int seed; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock (_global) seed = _global.Next(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _local = inst = new Random(seed); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return inst.Next(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;An AppDomain-wide Random instance is maintained in order to provide seeds for new Random instances created for any new threads that come along wanting random numbers.&amp;nbsp; Each thread maintains its own Random instance in a ThreadStatic field, such that once initialized, calls to Next need only retrieve the ThreadStatic Random instance and use its Next method; no locks are necessary, and sharing is minimized.&amp;nbsp; I tested this in a loop like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;Stopwatch sw; &lt;BR&gt;const int NUM = 1000000; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;while (true) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sw = Stopwatch.StartNew(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Parallel.For(0, NUM, i =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RandomGen1.Next(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(sw.Elapsed); &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sw = Stopwatch.StartNew(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Parallel.For(0, NUM, i =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RandomGen2.Next(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(sw.Elapsed); &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.ReadLine(); &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;On my dual-core laptop using .NET 3.5 and the June 2008 CTP of Parallel Extensions, the ThreadStatic approach ended up running twice as fast as the lock-based version.&amp;nbsp; Moreover, as the number of cores increases, so too will the amount of contention on the lock in the lock-based approach, thus increasing the gap between the two approaches.&amp;nbsp; Additionally, a lot of work has been done in .NET 4.0 to improve the performance of things such as accessing [ThreadStatic].&amp;nbsp; When I run this same code on current builds of .NET 4.0 (again on a dual-core), I see the ThreadStatic version running more than four times faster than the lock-based version.&amp;nbsp; Even when there’s no contention on the lock in the RandomGen1 solution (simulated by switching the parallel loops to sequential loops), the ThreadStatic version in .NET 4.0 still runs significantly faster than the lock-based version.&lt;/P&gt;
&lt;P&gt;Of course, if you really care about the quality of the random numbers, you should be using RNGCryptoServiceProvider, which generates cryptographically-strong random numbers &lt;EM&gt;(Addendum: davidacoder makes a good point in his comments on this post that while Random has certain statistical properties, using multiple Random instances as part of the same algorithm may change the statistical properties in unknown or undesirable ways)&lt;/EM&gt;.&amp;nbsp; For a look at how to get a Random-based facade for RNGCryptoServiceProvider, see &lt;A href="http://msdn.microsoft.com/en-us/magazine/cc163367.aspx" mce_href="http://msdn.microsoft.com/en-us/magazine/cc163367.aspx"&gt;.NET Matters: Tales from the CryptoRandom&lt;/A&gt; in the September 2007 issue of MSDN Magazine.&amp;nbsp; You could also settle on an intermediate solution, such as using an RNGCryptoServiceProvider to provide the seed values for the ThreadStatic Random instances in a solution like that in RandomGen2 (which would help to avoid another issue here, that of two threads starting with the same seed value due to accessing the global Random instance in the same time quantum):&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=consolas&gt;public static class RandomGen3&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static RNGCryptoServiceProvider _global = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new RNGCryptoServiceProvider();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ThreadStatic]&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static Random _local;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static int Next()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Random inst = _local;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (inst == null)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; byte[] buffer = new byte[4];&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _global.GetBytes(buffer);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _local = inst = new Random(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BitConverter.ToInt32(buffer, 0));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return inst.Next();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;} &lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9434171" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Concurrent, Multi-core Programming on Windows and .NET</title><link>http://blogs.msdn.com/pfxteam/archive/2008/10/27/9019731.aspx</link><pubDate>Tue, 28 Oct 2008 08:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9019731</guid><dc:creator>toub</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9019731.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9019731</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9019731</wfw:comment><description>&lt;P&gt;Thanks to everyone who attended our PDC pre-conference session yesterday on parallelism and concurrency!&amp;nbsp; We had a wonderful turnout at the event, and David, Joe, and I all had a terrific time. &lt;A class="" href="http://blogs.msdn.com/pfxteam/attachment/9019731.ashx" mce_href="http://blogs.msdn.com/pfxteam/attachment/9019731.ashx"&gt;Attached&lt;/A&gt; to this post are the slides we presented.&lt;/P&gt;
&lt;P&gt;(It turns out that the PDC site does allow you to &lt;A href="https://sessions.microsoftpdc.com/public/evals.aspx" mce_href="https://sessions.microsoftpdc.com/public/evals.aspx"&gt;submit an evaluation&lt;/A&gt; for a precon.&amp;nbsp; If you attended, we'd love your &lt;A href="https://sessions.microsoftpdc.com/public/evals.aspx" mce_href="https://sessions.microsoftpdc.com/public/evals.aspx"&gt;feedback&lt;/A&gt;.)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9019731" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pfxteam/attachment/9019731.ashx" length="1451170" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Talks/default.aspx">Talks</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/C_2B002B00_/default.aspx">C++</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Tools/default.aspx">Tools</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Release/default.aspx">Release</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CTP/default.aspx">CTP</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CDS/default.aspx">CDS</category></item><item><title>Feedback requested: TaskManager shutdown, Fair scheduling</title><link>http://blogs.msdn.com/pfxteam/archive/2008/08/01/8800195.aspx</link><pubDate>Fri, 01 Aug 2008 17:54:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8800195</guid><dc:creator>toub</dc:creator><slash:comments>19</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8800195.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8800195</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8800195</wfw:comment><description>&lt;p&gt;One of the primary reasons we've released CTPs of Parallel Extensions is to solicit feedback on the design and functionality it provides.&amp;#160; Does it provide all of the APIs you need to get your job done?&amp;#160; Are there scenarios you wished the APIs supported and that you need to work around in klunky ways?&amp;#160; And so forth.&amp;#160; We've received some terrific feedback thus far, we've already made changes based on it, we're currently making changes based on it, and we'll continue making changes based on it moving forward.&lt;/p&gt;  &lt;p&gt;We continually have discussions internally about additional support we could provide.&amp;#160; Frequently these discussions result in our needing to know more about our customers' needs.&amp;#160; There's a practically unlimited amount of functionality we could bake into Parallel Extensions, but each additional piece not only requires design, development, testing, and support, but it also can complicate other aspects of the design, potentially slow down other primary scenarios, and so forth.&amp;#160; In order to focus our efforts, we need feedback.&lt;/p&gt;  &lt;p&gt;Two such discussions occurred recently, and any feedback you provide would be useful in our deciding how to move forward.&lt;/p&gt;  &lt;p&gt;The first is about shutting down a TaskManager instance.&amp;#160; In the current implementation, we only support one kind of shutdown, which is triggered through a call to Dispose on TaskManager.&amp;#160; This implementation is a synchronous invocation that blocks until all of the Tasks previously scheduled to the TaskManager have completed.&amp;#160; However, there are other semantics we could potentially implement.&amp;#160; For example, we could provide an asynchronous shutdown option, that allowed you to asynchronously call Shutdown, and the TaskManager would only be disposed of when all of the tasks scheduled to it completed.&amp;#160; Or with a bit more internal reworking, we could support automatically canceling all of the tasks scheduled to the TaskManager.&amp;#160; And again that could be done synchronously (canceling all and then waiting for all) or asynchronously (canceling all and then only cleaning up after the TaskManager when any that were currently executing completed).&amp;#160; How useful would such capabilities be to you?&amp;#160; In what scenarios would you find them useful or, more importantly, necessary? Would such capabilities be dangerous at all in your scenarios?&lt;/p&gt;  &lt;p&gt;The second is about scheduling order.&amp;#160; One of the benefits that a work-stealing scheduler (the kind of scheduler employed by the Task Parallel Library) provides is a distribution of work across all cores, where each core prefers to schedule new work to and pull work from its local queue(s).&amp;#160; This scheduling can be made extremely efficient and can be made to improve locality and the like by using LIFO ordering, meaning that the task most recently scheduled is the one that will execute first.&amp;#160; This is separate from work scheduled to the scheduler from other threads (such as an application's main thread), which will typically still be scheduled in a generally FIFO order.&amp;#160; The question, then, is if there are scenarios you might have where you always want that FIFO-ish order, regardless of where the work is scheduled from.&amp;#160; Such an option would likely decrease performance in some key scenarios, but it would also be more fair in terms of the order in which work gets executed.&amp;#160; Do you have any scenarios that would require such a PreferFairness option?&amp;#160; We'd love to hear about them if you do.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8800195" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Feedback+Requested/default.aspx">Feedback Requested</category></item><item><title>PLINQ Ordering</title><link>http://blogs.msdn.com/pfxteam/archive/2008/06/11/8592301.aspx</link><pubDate>Thu, 12 Jun 2008 01:43:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8592301</guid><dc:creator>essey</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8592301.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8592301</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8592301</wfw:comment><description>&lt;p&gt;There is a natural tension between ordering and performance in a parallel partitioning system such as PLINQ, which we addressed as guidance in the Dec07 CTP documentation:&amp;#160; &amp;#8220;Although you can opt into ordering, this does come at a cost to performance because it constrains the options which PLINQ can use for executing a query, so it is better to avoid it in general if performance is your main concern. A better approach is to avoid assumptions on ordering in your programs where possible, or to explicitly sort elements in your query. This is consistent with the approach that most relational databases take.&amp;#8221;&amp;#160; &lt;/p&gt;  &lt;p&gt;In the June 2008 CTP, we did a major overall of the ordering model in PLINQ.&amp;#160; Here's an overview of our thinking, our rationale, and the design decisions that we made along the way.&amp;#160; As always, your feedback is very important.&amp;#160; We are especially looking for input regarding the default choice that we have made - to be unordered unless otherwise specified.&lt;/p&gt;  &lt;h3&gt;Importance of PERFORMANCE&lt;/h3&gt;  &lt;p&gt;PLINQ&amp;#8217;s &lt;em&gt;raison d&amp;#8217;etre&lt;/em&gt; is to provide improved performance to developers on multi-core systems.&amp;#160; As such, it is as the forefront of our mind when creating these systems.&amp;#160; Customers in many spaces that could make excellent use out of data parallelism do not have requirements on ordering, yet they would benefit from large performance gains.&amp;#160; &lt;/p&gt;  &lt;p&gt;This is certainly the case in the finance industry.&amp;#160; Financial institutions have told us that they could easily absorb 1000x increase in performance, and performance alone is what would drive them to adopt PLINQ (they don&amp;#8217;t even look to LINQ, because ease of programming is secondary in importance).&amp;#160; There are many scenarios that are pure number crunching and do not have expectations on ordering that need to be met.&amp;#160; &lt;/p&gt;  &lt;p&gt;There are other precedents in LINQ for having an unordered system: LINQ-to-SQL and other data providers do not provide a default ordering contract.&amp;#160; They require the end user to sort if this is necessary. &lt;/p&gt;  &lt;h3&gt;Importance of ORDER&lt;/h3&gt;  &lt;p&gt;On the other side, there are also reasons to support ordering in the system. &lt;/p&gt;  &lt;p&gt;1. &lt;strong&gt;LINQ-to-Objects sets the precedent&lt;/strong&gt; &amp;#8211; the original recipe, predecessor to PLINQ, does maintain ordering by default.&amp;#160; While some data providers no not require ordering, it still remains that PLINQ, for many scenarios, can be a drop-in replacement for LINQ-to-Objects.&amp;#160; I bet you didn&amp;#8217;t miss that caveat &amp;#8220;for many scenarios&amp;#8221;, which draws attention to what we have dubbed the Parallelism Blockers.&amp;#160; Again from the CTP documentation, note #4:&amp;#160; &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;A very common question is: Why is an explicit programming model needed for concurrency instead of having the system automatically decide to provide parallelism? &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;There are several reasons why there needs to be some programmer involvement in the parallelism process:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;1.&amp;#160;&amp;#160;&amp;#160; Mutable data structures and impurity      &lt;br /&gt;2.&amp;#160;&amp;#160;&amp;#160; Concurrent exceptions       &lt;br /&gt;3.&amp;#160;&amp;#160;&amp;#160; Thread affinity       &lt;br /&gt;4.&amp;#160;&amp;#160;&amp;#160; Ordering expectations       &lt;br /&gt;5.&amp;#160;&amp;#160;&amp;#160; Performance - Problems with &amp;lt; 1.0 speedup &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;2. &lt;strong&gt;Some code expects ordering&lt;/strong&gt; - As an illustration, this can provide unexpected behavior in code such as:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p class="MsoListParagraphCxSpFirst" style="tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;Array.Sort(a); &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p class="MsoListParagraphCxSpLast" style="tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;var q = from x in a ...; &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p class="MsoListParagraphCxSpLast" style="tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The initial Array.Sort's demand on order would not be kept by the system, and it would be shuffled in the query execution by default. PLINQ provides mechanisms to preserve ordering, but usually at a cost to performance. So, you can opt-in to order preservation in PLINQ explicitly: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p class="MsoListParagraphCxSpFirst" style="tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;Array.Sort(a); &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p class="MsoListParagraphCxSpLast" style="tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;from x in a.AsParallel().AsOrdered() ... &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;3. &lt;strong&gt;Some operators require or insist on ordering&lt;/strong&gt; &amp;#8211; The OrderBy and ThenBy operators specify ordering.&amp;#160; If these were disregarded and ignored after being declared, many scenarios would be cut off.&amp;#160; For this reason, these turn on ordering that flows forward in the system. &lt;/p&gt;  &lt;p&gt;Further, operators such as Reverse, SequenceEquals, TakeWhile, SkipWhile, and Zip lose practical purposes when there is not a defined ordering.&amp;#160; Since these operators are useful in many cases, it is important to keep them. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Our Goals&lt;/h3&gt;  &lt;p&gt;These goals are the list of requirements that must be achieved to successfully address this tension.&amp;#160; These are listed in no particular order and are not ranked.&amp;#160; They must all be achieved. &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Transparent, clear mental model for developers&lt;/strong&gt; &amp;#8211; The developer should be able to understand the system through a very clear and succinctly stated design statement.&amp;#160; There should not be exceptions to this.&amp;#160; It should be straight-forward and simple to write code against. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Good default&lt;/strong&gt; &amp;#8211; There should be a default model that works for the important customer cases as determined by the group.&amp;#160; For Dev10 this is for Finance and Multimedia scenarios.&amp;#160; A good default also means that there is nothing additional that needs to be specified in the opt-in mechanism (i.e. AsParallel() without any parameters should be sufficient). &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Flexibility to address both sides of the performance/ordering tension&lt;/strong&gt; &amp;#8211; While the model does pick a default, scenarios that favor the other side of the tension should be able to toggle in all or parts of the query.&amp;#160; &lt;/li&gt; &lt;/ol&gt;  &lt;h3&gt;Non-Goals&lt;/h3&gt;  &lt;p&gt;These are the things that we are not explicitly trying to accomplish nor avoid; they are not the main purpose of this design.&amp;#160; If they happen along the way, they happen.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Map completely to LINQ-to-Objects or another provider &lt;/strong&gt;&amp;#8211; There is no specific ordering or full set of operators contract required for the LINQ-specification, and it is not a goal to strictly adhere to another provider.&amp;#160; It is more important to adhere to a customer scenario. &lt;/li&gt; &lt;/ol&gt;  &lt;h3&gt;The New Mental Model&lt;/h3&gt;  &lt;p&gt;The mental model is the suggested way for the developer to think of the system.&amp;#160; How it is actually implemented under the covers may differ from this, as long as the end results align with user expectations, consistent with the mental model. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;The mental model is succinctly:&lt;/em&gt; &lt;/p&gt;  &lt;p&gt;Ordering operators re-establish order, shuffle points shuffle the order.    &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;And more detailed:&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;a.&amp;#160;&amp;#160;&amp;#160; The query is shuffled at the start    &lt;br /&gt;b.&amp;#160;&amp;#160;&amp;#160; unless the default is overridden to keep the order at the start     &lt;br /&gt;c.&amp;#160;&amp;#160;&amp;#160; ordering operators establish a new ordering that flows afterwards in the query,     &lt;br /&gt;d.&amp;#160;&amp;#160;&amp;#160; a shuffle point can be inserted anywhere in the query, reshuffling the query,     &lt;br /&gt;e.&amp;#160;&amp;#160;&amp;#160; until there is another (optional) ordering operator&amp;#8230; &lt;/p&gt;  &lt;h3&gt;Default: unordered&lt;/h3&gt;  &lt;p&gt;In favor of performance, PLINQ&amp;#8217;s &lt;em&gt;raison d&amp;#8217;etre&lt;/em&gt;, the default for queries is to be &lt;strong&gt;unordered&lt;/strong&gt;.&amp;#160; &lt;/p&gt;  &lt;p&gt;Rationale for this is covered above.&amp;#160; This is a decision that we will validate through performance work and feedback from you.&amp;#160; This is not a clear-cut decision and the right data could persuade us.&amp;#160; If you have good reasons to keep or change this default, please let us know.&amp;#160; What do you think the default should be and why?&amp;#160; &lt;/p&gt;  &lt;h3&gt;Programming Model Implications&lt;/h3&gt;  &lt;p&gt;To provide a richer programming model for working with ordering, there are mechanisms to override the default and turn ordering on and off in the query.&amp;#160; &lt;/p&gt;  &lt;p&gt;This specification announces the addition of AsOrdered and AsUnordered operators to the PLINQ syntax and the removal of the ParallelQueryOptions enum and all overloads of AsParallel that accept this enum.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Overriding the default&lt;/h4&gt;  &lt;p&gt;Call AsOrdered on an IEnumerable or IList to opt into PLINQ preserving the input ordering. &lt;/p&gt;  &lt;p&gt;AsOrdered can only be validly invoked on AsParallel, Range, and Repeat operators.&amp;#160; Any other operators will throw a runtime InvalidOperationException.&amp;#160; &lt;/p&gt;  &lt;p&gt;New to the ParallelEnumerable static class is: &lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 9pt; color: blue; font-family: consolas; mso-bidi-font-size: 10.0pt"&gt;public&lt;/span&gt;&lt;span style="font-size: 9pt; font-family: consolas; mso-bidi-font-size: 10.0pt"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: green"&gt;IParallelEnumerable&amp;lt;TSource&amp;gt;&lt;/span&gt; &lt;b style="mso-bidi-font-weight: normal"&gt;AsOrdered&lt;/b&gt;&amp;lt;&lt;span style="color: green"&gt;TSource&lt;/span&gt;&amp;gt;(&lt;span style="color: green"&gt;IParallelEnumerable&amp;lt;TSource&amp;gt;&lt;/span&gt; &lt;b style="mso-bidi-font-weight: normal"&gt;source&lt;/b&gt;);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;Usage examples: &lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;src.AsParallel().AsOrdered().Take(1000)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;ParallelEnumerable.Range(1,1000000000).AsOrdered().Take(1000) &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;ParallelEnumerable.Repeat(2,1000000000).AsOrdered().Take(1000)&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;  &lt;h4&gt;Shuffling midquery&lt;/h4&gt;  &lt;p&gt;If, mid-query, a point is reach where the developer knows that ordering is no longer important, the developer can add a shuffle point to tell the query engine that ordering can now be arbitrary.&amp;#160; A new operator is added to PLINQ for this purpose.&amp;#160; &lt;/p&gt;  &lt;p&gt;New to the ParallelEnumerable static class is: &lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 9pt; color: blue; font-family: consolas; mso-bidi-font-size: 10.0pt"&gt;public&lt;/span&gt;&lt;span style="font-size: 9pt; font-family: consolas; mso-bidi-font-size: 10.0pt"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: green"&gt;IParallelEnumerable&amp;lt;TSource&amp;gt;&lt;/span&gt; &lt;b style="mso-bidi-font-weight: normal"&gt;AsUnordered&lt;/b&gt;&amp;lt;&lt;span style="color: green"&gt;TSource&lt;/span&gt;&amp;gt;(&lt;span style="color: green"&gt;IParallelEnumerable&amp;lt;TSource&amp;gt;&lt;/span&gt; &lt;b style="mso-bidi-font-weight: normal"&gt;source&lt;/b&gt;);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;It can be used as follows: &lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;pages.AsParallel().AsOrdered().Take(1000000)&lt;/span&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;.&lt;span style="background: aqua; mso-highlight: aqua"&gt;AsUnordered&lt;/span&gt;().Join(&amp;#8230;).Select(&amp;#8230;); &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;In this case, the query no longer requires ordering for the following Join and Select, which are the heavy lifting of the query.    &lt;br /&gt;&lt;/p&gt;  &lt;h4&gt;Turning on ordering midquery&lt;/h4&gt;  &lt;p&gt;Ordering can be turned on, then off, then on again midquery: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;On: Using original LINQ operators OrderBy or OrderByDescending and then optionally ThenBy or ThenByDescending operators will establish ordering in the query that will continue to flow throughout.&amp;#160; Take for example: &lt;/li&gt; &lt;/ul&gt;  &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;pages.AsParallel().Where(&amp;#8230;).Select(&amp;#8230;)&lt;/span&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;.&lt;span style="background: aqua; mso-highlight: aqua"&gt;OrderBy&lt;/span&gt;(i =&amp;gt; i.rank).Take(10); &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;In the above query, the Where and the Select operators can function in arbitrary order, then the pages are ordered by rank for the Take operator to return the top 10 pages by rank. &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Then Off: This ordering requirement is lifted at the next shuffle point if there is one.&amp;#160; &lt;/li&gt; &lt;/ul&gt;  &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;pages.AsParallel().Where(&amp;#8230;).Select(&amp;#8230;).OrderBy(i =&amp;gt; i.rank).Take(10000)&lt;/span&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;.&lt;span style="background: aqua; mso-highlight: aqua"&gt;AsUnordered&lt;/span&gt;().Join(&amp;#8230;); &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p class="MsoNormal" style="margin-left: 0.5in; text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;In the above example, the initial parts of the query remain the same as above, but the query no longer needs to maintain the ordering when performing the Join operator. &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Then On again: This ordering requirement is reset at a subsequent ordering operator. &lt;/li&gt; &lt;/ul&gt;  &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;pages.AsParallel().Where(&amp;#8230;).Select(&amp;#8230;).OrderBy(i =&amp;gt; i.rank).Take(10000)&lt;/span&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;.AsUnordered().Join(&amp;#8230;)&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;.&lt;span style="background: aqua; mso-highlight: aqua"&gt;OrderBy&lt;/span&gt;(i =&amp;gt; i.domain); &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p class="MsoNormal" style="text-indent: 0.5in"&gt;&lt;span style="font-family: " new??="new??" courier="courier"&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;In the above example, ordering is turned on again at the end to reorder by domain for the output. &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8592301" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category></item><item><title>Parallel loop performance</title><link>http://blogs.msdn.com/pfxteam/archive/2008/03/12/8179013.aspx</link><pubDate>Thu, 13 Mar 2008 08:57:49 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8179013</guid><dc:creator>toub</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8179013.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8179013</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8179013</wfw:comment><description>&lt;p&gt;We've received several questions on the &lt;a href="http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=1986&amp;amp;SiteID=1"&gt;MSDN Forums&lt;/a&gt; for Parallel Extensions about the performance of the Parallel class, and specifically of the loop constructs we provided in the CTP.&amp;nbsp; We're very much aware that the performance of Parallel.For/ForEach in the CTP is not optimal, and that for some situations, the overhead for these constructs will be too much for a variety of situations.&amp;nbsp; That's ok: we released the preview of the Task Parallel Library in the December CTP to solicit early feedback on the APIs we're providing (e.g. Are they useful?&amp;nbsp; What's missing? etc.), and to do so and to get the preview out early, we did so at the expense of performance and reliability (it is a technology preview, after all).&amp;nbsp; We'll be spending a whole lot of time getting the performance of these loops to be stellar; for now, please let us know whether the APIs are right so that we can adjust if they're not.&amp;nbsp; And if you have interesting situations where the performance isn't great, we'd love to know about that, too, so that we factor that in when determining the best implementations to ship.&lt;/p&gt; &lt;p&gt;That said, there will always be some cases that we won't handle perfectly, due simply to the sheer number of variations and use cases that exist.&amp;nbsp; And for those situations, we provide the lower-level Task construct with its replication capabilities to allow you to write custom loops that are best suited to your specific needs (as an example, we previously posted about how to write a &lt;a href="http://blogs.msdn.com/pfxteam/archive/2008/02/27/7919786.aspx"&gt;parallel while loop&lt;/a&gt;).&lt;/p&gt; &lt;p&gt;Consider another situation: you want a for loop, but the body of the for loop contains so little work that even the cost of a delegate invocation (to execute the body) is too much.&amp;nbsp; For example, consider this implementation of a very simple ParallelFor loop:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;static&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ParallelFor(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int&lt;/span&gt; fromInclusive, &lt;span style="color: blue"&gt;int&lt;/span&gt; toExclusive, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;int&lt;/span&gt;&amp;gt; body)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; index = fromInclusive;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.Create(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; i;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; ((i = &lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Increment(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;ref&lt;/span&gt; index) - 1) &amp;lt; toExclusive)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;body(i);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}, &lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskCreationOptions&lt;/span&gt;.SelfReplicating).Wait();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;For loop bodies with a significant amount of work, this implementation isn't all that bad.&amp;nbsp; But for small bodies, there is a fairly large overhead here per iteration, in that each iteration incurs both an interlocked operation (to advance the index variable) and a delegate invocation (to run the body).&amp;nbsp; Following this same approach, I could cut down on the number of interlocked operations by incrementing each time by an amount larger than 1:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;static&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ParallelFor(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int&lt;/span&gt; fromInclusive, &lt;span style="color: blue"&gt;int&lt;/span&gt; toExclusive, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;int&lt;/span&gt;&amp;gt; body)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;const&lt;/span&gt; &lt;span style="color: blue"&gt;int&lt;/span&gt; STRIDE = 8;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; index = fromInclusive;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.Create(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; i;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; ((i = &lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Add(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;ref&lt;/span&gt; index, STRIDE) - STRIDE) &amp;lt; toExclusive)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; endExclusive = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;Math&lt;/span&gt;.Min(i + STRIDE, toExclusive);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt;(; i&amp;lt;endExclusive; i++)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;body(i);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;},&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskCreationOptions&lt;/span&gt;.SelfReplicating).Wait();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;In spirit, this is actually very similar to the implementation of Parallel.For in the CTP (which, based on my previous comments about CTP performance, should hint at the performance quality of this example ;).&amp;nbsp; Each CPU grabs 8 elements using an interlocked addition.&amp;nbsp; This decreases the number of interlocked operations per iteration from 1 to approximately 1/8, but it does so at the expense of load balancing.&amp;nbsp; And still, for each iteration we have the cost of a delegate invocation in order to execute the body of the loop as provided by the caller.&amp;nbsp; In fact, no matter what we do here, with this overall design of ParallelFor, we won't be able to avoid that delegate invocation, which could be prohibitive for certain problems with very, very small bodies.&lt;/p&gt; &lt;p&gt;To fix that, we could go with a different design:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; color: blue; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;static&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ParallelForRange(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int&lt;/span&gt; fromInclusive, &lt;span style="color: blue"&gt;int&lt;/span&gt; toExclusive, &lt;span style="color: #2b91af"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Action&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;int&lt;/span&gt;, &lt;span style="color: blue"&gt;int&lt;/span&gt;&amp;gt; body);&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The idea here is that rather than providing a loop body that accepts the current iteration, the loop body accepts two integers, one representing the start of a range and the other representing the end (just as with fromInclusive and toExclusive, but on a smaller scale):&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;static&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ParallelForRange(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int&lt;/span&gt; fromInclusive, &lt;span style="color: blue"&gt;int&lt;/span&gt; toExclusive, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;int&lt;/span&gt;, &lt;span style="color: blue"&gt;int&lt;/span&gt;&amp;gt; body)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;const&lt;/span&gt; &lt;span style="color: blue"&gt;int&lt;/span&gt; STRIDE = 8;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; index = fromInclusive;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.Create(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; i;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; ((i = &lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Add(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;ref&lt;/span&gt; index, STRIDE) - STRIDE) &amp;lt; toExclusive)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;body(i, &lt;span style="color: #2b91af"&gt;Math&lt;/span&gt;.Min(i + STRIDE, toExclusive));&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;},&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskCreationOptions&lt;/span&gt;.SelfReplicating).Wait();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;To use this, rather than doing the following as you would with the ParallelFor method:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;ParallelFor(0, N, i =&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: green"&gt;// original loop body here&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;});&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;you could do the following:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;ParallelForRange(0, N, (fromInclusive, toExclusive) =&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt; (&lt;span style="color: blue"&gt;int&lt;/span&gt; i = fromInclusive; i &amp;lt; toExclusive; i++)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: green"&gt;// original loop body here&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;});&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Just as with the previous ParallelFor implementation, where we used a stride to decrease the number of interlocked operations, here in ParallelForRange we've used that same stride to decrease the number of delegate invocations, at the expense of forcing the user to implement their own loop inside of the parallel loop.&lt;/p&gt; &lt;p&gt;Now, as previously mentioned, this striding approach has a downside of decreasing the possibility for load balancing.&amp;nbsp; The implementation of Parallel.For that we eventually ship will do its best to both decrease overhead per iteration and maximize load balancing.&amp;nbsp; But there may still be cases where the cost of the delegate invocation per iteration will be too much.&amp;nbsp; Forgetting the implementation details for a moment, would it be useful for you if in addition to Parallel.For, we also provided a Parallel.ForRange with a design similar to the method I just showed? We'd love your feedback on issues like this, as we want to make sure we're providing the right solutions for your problem domain.&amp;nbsp; And are there other common looping constructs that you'd like to see us provide?&amp;nbsp; Now is a great time to download the CTP, try it out, and send us your feedback... we're listening.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8179013" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category></item><item><title>Ordering the output of parallel computations</title><link>http://blogs.msdn.com/pfxteam/archive/2008/03/11/8165836.aspx</link><pubDate>Wed, 12 Mar 2008 07:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8165836</guid><dc:creator>toub</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8165836.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8165836</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8165836</wfw:comment><description>&lt;P&gt;Frequently when attempting to do multiple operations in parallel, ordering becomes an issue.&amp;nbsp; Consider an application where I'm rendering and writing out to a video file frames of a movie:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;for&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; numberOfFrames; i++)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; frame = GenerateFrame(i);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;WriteToMovie(frame);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;For a bit of pizzazz, I'll show the same thing with LINQ:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; frames = &lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; i &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, numberOfFrames)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt; GenerateFrame(i);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;foreach&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; frame &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; frames) WriteToMovie(frame);&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now, my GenerateFrame method is expensive and computationally intensive, so I'd like to generate frames in parallel. For this example, we'll assume that my GenerateFrame method is thread-safe and can be called concurrently (rendering one frame doesn't modify any state used to render another frame), but access to my WriteToMovie method must be serialized:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;using&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: #2b91af"&gt;ManualResetEvent&lt;/SPAN&gt; mre = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ManualResetEvent&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;))&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; count = numberOfFrames;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt; obj = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; numberOfFrames; i++)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ThreadPool&lt;/SPAN&gt;.QueueUserWorkItem(state =&amp;gt;&lt;SPAN style="COLOR: blue"&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; frame = GenerateFrame((&lt;FONT color=#0000ff&gt;int&lt;/FONT&gt;)state);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;lock&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;(obj) &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;WriteToMovie(frame);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;?xml:namespace prefix = o /&gt;&lt;o:p&gt;&amp;nbsp;&lt;BR&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #2b91af"&gt;Interlocked&lt;/SPAN&gt;.Decrement(&lt;SPAN style="COLOR: blue"&gt;ref&lt;/SPAN&gt; count) == 0) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}, state);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;mre.WaitOne();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Unfortunately, that's quite a bit of code overhead, and it also suffers from a fundamental ordering problem: the frames may end up being written to the output movie file in an arbitrary order, based on when the frame generation completes.&amp;nbsp; A version with this ordering issue fixed might look like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; frames = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Bitmap&lt;/SPAN&gt;[numberOfFrames];&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; events = (&lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; i &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, numberOfFrames)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ManualResetEvent&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;)).ToArray();&lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;for&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; numberOfFrames; i++)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ThreadPool&lt;/SPAN&gt;.QueueUserWorkItem(state =&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; frameNum = (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;)state;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;frames[frameNum] = GenerateFrame(frameNum);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;events[frameNum].Set();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}, i);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;BR&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;for&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; numberOfFrames; i++)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;events[i].WaitOne();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;WriteToMovie(frames[i]);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This has the general effect I want, but there are still some unfortunately overheads here (for example, I'm creating, setting, and waiting on a ManualResetEvent per frame). It's also verbose.&amp;nbsp; Instead, I can use Future&amp;lt;T&amp;gt; from &lt;A href="http://msdn2.microsoft.com/en-us/concurrency/default.aspx" mce_href="http://msdn2.microsoft.com/en-us/concurrency/default.aspx"&gt;Parallel Extensions&lt;/A&gt; to solve the same problem:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; frames = (&lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; i &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, numberOfFrames)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; GenerateFrame(i))).&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ToArray();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;foreach&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; frame &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; frames) WriteToMovie(frame.Value);&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I love how close this is to the original LINQ version (and how much less code it is the than my previous ThreadPool sample).&amp;nbsp; Rather than selecting GenerateFrame(i), I'm selecting Future.Create(() =&amp;gt; GenerateFrame(i)), and rather than calling WriteToMovie(frame), I'm calling WriteToMovie(frame.Value).&amp;nbsp; With those changes, the frames are now being computed in parallel (note I'm also using ToArray to calls the entire query to be enumerated), and they're being written out to the movie file in the correct order without having to do any explicit locking or coordination.&amp;nbsp; Sweet!&lt;/P&gt;
&lt;P&gt;If I wanted to, I could do the same thing without LINQ, tracking the collection of futures explicitly:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; frames = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Queue&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Bitmap&lt;/SPAN&gt;&amp;gt;&amp;gt;();&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;for&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; numberOfFrames; i++)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;/SPAN&gt;num = i;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;frames.Enqueue(&lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; GenerateFrame(num)));&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;while&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (frames.Count &amp;gt; 0) WriteToMovie(frames.Dequeue().Value);&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I could also use PLINQ:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; frames = &lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; i &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, numberOfFrames).&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsParallel(&lt;SPAN style="COLOR: #2b91af"&gt;ParallelQueryOptions&lt;/SPAN&gt;.PreserveOrdering)&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt; GenerateFrame(i);&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;foreach&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; frame &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; frames) WriteToMovie(frame);&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Three different approaches to solving the same problem with Parallel Extensions, and all of them requiring less code (and less complicated code) than my ThreadPool example.&amp;nbsp; Just makes you smile, doesn't it? :)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8165836" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category></item><item><title>Task Parallel Library on Channel 9</title><link>http://blogs.msdn.com/pfxteam/archive/2008/02/19/7804314.aspx</link><pubDate>Wed, 20 Feb 2008 01:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7804314</guid><dc:creator>toub</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/7804314.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=7804314</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=7804314</wfw:comment><description>&lt;P&gt;Charles from Channel 9 sat down with several of us from the&amp;nbsp;Parallel Computing Platform team&amp;nbsp;to discuss the Task Parallel Library component of Parallel Extensions.&amp;nbsp;A video of the conversation is&amp;nbsp;now available on Channel9: &lt;A href="http://channel9.msdn.com/Showpost.aspx?postid=384229"&gt;http://channel9.msdn.com/Showpost.aspx?postid=384229&lt;/A&gt;. We hope you like it, and as always, feedback is welcome and appreciated!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7804314" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Media/default.aspx">Media</category></item><item><title>Recursion and Concurrency</title><link>http://blogs.msdn.com/pfxteam/archive/2008/01/31/7357135.aspx</link><pubDate>Thu, 31 Jan 2008 22:55:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7357135</guid><dc:creator>toub</dc:creator><slash:comments>19</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/7357135.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=7357135</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=7357135</wfw:comment><description>&lt;p&gt;When&amp;nbsp;teaching recursion in an introductory computer science course, one of the most common examples used involves a tree data structure.&amp;nbsp; Trees are useful in this regard as they are simple and recursive in nature, with a tree's children also being trees, and allow for teaching different kinds of traversals (in-order, pre-order, post-order, level-order, and so forth).&amp;nbsp; But when these introductory concepts meet multithreading, the concepts are no longer so simple, at least not with the tools available in mainstream languages today like C#, C++, and Java. Consider a simple Tree data structure:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;class&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; Left, Right; &lt;/span&gt;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;// children&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;public&lt;/span&gt; T Data; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;// data for this node&amp;nbsp;&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Let's say we want to execute an Action&amp;lt;T&amp;gt; for each datum stored in the tree, and let's assume I don't care about order (introducing parallelism could be questionable if I did).&amp;nbsp; That's straightforward to do sequentially and recursively:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process the current node, then the left,&amp;nbsp;then the right&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(tree.Data);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Left, action);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Right, action);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I could also do so without recursion by maintaining&amp;nbsp;an explicit stack (or queue, or some other data structure with different ordering guarantees):&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; toExplore = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Stack&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt;();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Start with the root node&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(tree);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; (toExplore.Count &amp;gt; 0)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Grab the next node, process it, and push its children&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; current = toExplore.Pop();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(current.Data);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt; (current.Left != &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(current.Left);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt; (current.Right != &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(current.Right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;?xml:namespace prefix = o /&gt;&lt;o:p&gt;Now, let's assume the action we're performing on each node of the tree is independent, relatively expensive and/or that the tree is relatively large, and as such we want to process the tree in parallel (we're of course also assuming that the action delegate is thread-safe), meaning that we want multiple threads each running the action delegate on distinct tree nodes.&amp;nbsp; How do we do this with what we have in .NET today?&lt;/o:p&gt;&lt;/p&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;There are multiple approaches, some more valid than others.&amp;nbsp; The first thing someone might try is to follow the original recursive implementation but using the ThreadPool, which could look something like this:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Use an event to prevent this method from&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // returning until its children have completed&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: blue"&gt;var &lt;/span&gt;mre = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;))&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process the left&amp;nbsp;child asynchronously&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Left, action);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;});&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process current node and right child synchronously&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;action(tree.Data);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Right, action);&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Wait for the left child&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.WaitOne();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;The idea behind this implementation is to, given a node, spin up a work item to process that node's left child in parallel with the current node, and then process the current node's data as well as its right child.&amp;nbsp; Of course, I could be losing out on some parallelism here as I delay processing of the right child until I'm done processing the current data.&amp;nbsp; So we modify it slightly:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Use an event to wait for the children&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: blue"&gt;var&lt;/span&gt; mre = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;))&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; count = 2;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process the left child asynchronously&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Left, action);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;});&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process the right child asynchronously&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Right, action);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;});&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process the current node synchronously&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(tree.Data);&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Wait for the children&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.WaitOne();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;I've now fixed that issue, such that both the left and the right children could potentially be processed in parallel with the current node, but that was by far not the worst problem.&amp;nbsp; For starters, I'm creating a ManualResetEvent for every node in the tree... that's expensive.&amp;nbsp; ManualResetEvent is a thin wrapper around a Win32 kernel event primitive, so creating one of these things requires kernel transitions, as does setting and waiting on one.&amp;nbsp; Next, every time I process a node, I block waiting for its children to complete.&amp;nbsp; And as the processing of a node (all but the root) is happening on a thread from the ThreadPool, I'm blocking ThreadPool threads.&amp;nbsp; If a ThreadPool thread gets blocked, the ThreadPool will need to inject additional threads in order to process the remaining work items, and thus this implementation will require approximately one thread from the pool per node in the tree.&amp;nbsp; That's a lot of threads!&amp;nbsp; And that carries with it some serious problems.&amp;nbsp; By default, a thread in .NET has a megabyte of stack space committed for it, so each thread burns a megabyte of (virtual) memory.&amp;nbsp; The ThreadPool also throttles the creation of additional threads, such that introducing a new thread (once the number of pool threads equals the number of processors) will take 500 ms.&amp;nbsp; For a tree of 250 nodes, that means its processing will take close to 2 minutes, purely for the overhead of creating threads, nevermind the actual processing of the nodes.&amp;nbsp; And worse, there is a maximum number of threads in the pool: in .NET, the ThreadPool has a limited number of threads, by default 25 per processor in .NET 1.x/2.0 and 250 per processor in .NET 2.0 SP1.&amp;nbsp; If the pool reaches the maximum, no new threads will be created, and thus this implementation could deadlock.&amp;nbsp; Parent nodes will be waiting for their child nodes to complete, but the child nodes can't be processed until their parent nodes complete and relinquish a thread from the pool to execute.&lt;/o:p&gt;&lt;/p&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;Obviously, we need a better implementation. Next up, we can walk the tree sequentially, queuing up a work item in the pool for each node in the tree.&amp;nbsp; Here we take that approach based on the recursive implementation of a tree walk:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Use an event to wait for all of the nodes to complete&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: blue"&gt;var&lt;/span&gt; mre = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;))&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; count = 1;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Recursive delegate to walk the tree&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt; processNode = &lt;span style="color: blue"&gt;null&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;processNode = node =&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (node == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Asynchronously&amp;nbsp;run the action on&amp;nbsp;the current node&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Increment(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(node.Data);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;});&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process the&amp;nbsp;children&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;processNode(node.Left);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;processNode(node.Right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;};&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Start off with the root node&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;processNode(tree);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Signal that no&amp;nbsp;more&amp;nbsp;work items will be created&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) mre.Set();&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Wait for all of the work to complete&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.WaitOne();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;This implementation is better from a resources perspective and won't lead to the same kind of deadlocks as in the previous example.&amp;nbsp; We're still creating a work item for each node, but now the work item is simply to asynchronously execute the action on the node's data, whereas the tree walk itself is still happening sequentially on the main thread (taking advantage of a recursive delegate).&amp;nbsp; To maintain blocking behavior&amp;nbsp;similar to&amp;nbsp;the previous examples (where the call to Process won't return until all of the work has completed) though not identical (the processing of children nodes don't block the parent), a counter is incremented before each work item is created and is decremented when each work item finishes; only when that counter reaches 0 will the main thread continue (note how we need to start the counter at 1 and then decrement it after all of the work items have been created... this is to ensure that a work item completing before all of the work has been kicked off doesn't set the event prematurely).&amp;nbsp; We can&amp;nbsp;take the same approach &lt;/o:p&gt;&lt;o:p&gt;with a variant of the iterative implementation shown earlier:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp;Use an event to wait for all of the nodes&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // to complete&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: blue"&gt;var &lt;/span&gt;mre = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;))&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; count = 1;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Start with the root node&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; toExplore = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Stack&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt;();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(tree);&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Process all of the nodes&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; (toExplore.Count &amp;gt; 0)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Get the current node and and push its children&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; current = toExplore.Pop();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&lt;/span&gt; (current.Left != &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(current.Left);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt; (current.Right != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;toExplore.Push(current.Right);&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Asynchronously process the&amp;nbsp;data&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Increment(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(current.Data);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;});&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Signal that no more work items will&amp;nbsp;be created&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) mre.Set();&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Wait for all work items to be completed&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.WaitOne();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;These approaches work by queueing a work item per node in the tree.&amp;nbsp; &lt;/o:p&gt;&lt;o:p&gt;There are, of course, other approaches.&amp;nbsp; Rather than adding a work item per node, we can create N work items, and have each work item process approximately 1/Nth of the nodes in the tree, where N is the number of threads.&amp;nbsp; For example, we could store all of the nodes into a list and then split that list into N pieces and have a work item process each piece:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Create a list of all nodes in the tree&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; nodes = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt;();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; toExplore = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Stack&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt;();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(tree);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; (toExplore.Count &amp;gt; 0)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; current = toExplore.Pop();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;nodes.Add(current);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt; (current.Left != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(current.Left);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt; (current.Right != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;toExplore.Push(current.Right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Divide the list up into chunks&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; workItems = &lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.ProcessorCount;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; chunkSize = &lt;span style="color: #2b91af"&gt;Math&lt;/span&gt;.Max(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nodes.Count / workItems, 1);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; count = workItems;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Use an event to wait for all work items&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;&lt;/span&gt;mre = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Each work item processes appx 1/Nth of the&amp;nbsp;data items&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WaitCallback&lt;/span&gt; callback = state =&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; iteration = (&lt;span style="color: blue"&gt;int&lt;/span&gt;)state;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; from = chunkSize * iteration;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue"&gt;int&lt;/span&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;to = iteration == workItems - 1 ?&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nodes.Count : &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;chunkSize * (iteration + 1);&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; (from &amp;lt; to) action(nodes[from++].Data);&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;};&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;The ThreadPool is&amp;nbsp;used to process all but one of the &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // chunks; the current thread is used for that chunk, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // rather than just blocking.&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt; (&lt;span style="color: blue"&gt;int&lt;/span&gt; i = 0; i&amp;lt;workItems; i++)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (i &amp;lt; workItems-1) &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(callback, i);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;else&lt;/span&gt; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; callback(i);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Wait for all work to complete&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.WaitOne();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;Rather than statically dividing the work up, I could also rewrite the code such that each of the work items themselves is responsible for pulling work to handle:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Get an enumerator for the tree&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerator&lt;/span&gt;&amp;lt;T&amp;gt; enumerator = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GetNodes(tree).GetEnumerator();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; workItems = &lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.ProcessorCount;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; count = workItems;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Use an event to wait for all work&amp;nbsp;items &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;to complete&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: blue"&gt;var&lt;/span&gt; mre = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;))&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Each work item will continually pull data from the &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // enumerator and process it until there is no more data&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // to process&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WaitCallback&lt;/span&gt; callback = &lt;span style="color: blue"&gt;delegate&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt; (&lt;span style="color: blue"&gt;true&lt;/span&gt;)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;T data;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;lock&lt;/span&gt; (enumerator)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (!enumerator.MoveNext())&lt;span style="color: blue"&gt; break&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;data = enumerator.Current;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(data);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Interlocked&lt;/span&gt;.Decrement(&lt;span style="color: blue"&gt;ref&lt;/span&gt; count) == 0)&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.Set();&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;};&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;The ThreadPool is&amp;nbsp;used to process all but one of the &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // chunks; the current&amp;nbsp; thread is used for that chunk,&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// rather than just blocking.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt; (&lt;span style="color: blue"&gt;int&lt;/span&gt; i = 0; i &amp;lt; workItems; i++)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (i &amp;lt; workItems-1)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;callback, i);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;else&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;callback(i);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;Wait for all work to complete&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;mre.WaitOne();&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;o:p&gt;&lt;br&gt;&lt;span style="font-size: 10pt; color: green; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;//&amp;nbsp;An enumerator for a tree&lt;/span&gt;&lt;br&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;T&amp;gt; GetNodes&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;yield&lt;/span&gt; &lt;span style="color: blue"&gt;return&lt;/span&gt; tree.Data;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue"&gt;var&lt;/span&gt; data &lt;span style="color: blue"&gt;in&lt;/span&gt; GetNodes(tree.Left))&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue"&gt;yield&lt;/span&gt; &lt;span style="color: blue"&gt;return&lt;/span&gt; data;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue"&gt;var&lt;/span&gt; data &lt;span style="color: blue"&gt;in&lt;/span&gt; GetNodes(tree.Right))&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="color: blue"&gt;yield&lt;/span&gt; &lt;span style="color: blue"&gt;return&lt;/span&gt; data;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;Here I use a C# iterator to create an enumerator for all of the nodes in the tree.&amp;nbsp; A work item is queued for each processor, and each of those work items retrieves an item from the enumerator, processes it, and goes back for more.&amp;nbsp; Since multiple threads are accessing the enumerator (which isn't thread-safe), retrieving an item from it must be done under lock.&amp;nbsp; Unfortunately, that's expensive; a better implementation would shift to grabbing more items from the enumerator so that the lock could be taken fewer times.&lt;/p&gt; &lt;p class="MsoNormal"&gt;There are still further possible approaches.&amp;nbsp; For example, we could walk the tree until we get to nodes of a certain depth (such as the log of the number of cores) and then process all of the subtrees at that depth in parallel with each other.&lt;/p&gt; &lt;p class="MsoNormal"&gt;All of these implementations also have potential locality issues.&amp;nbsp; It's reasonable to assume (though certainly not guaranteed) that nodes in the tree near to each other were created near to each other in time and are likely near to each other in memory (this assumption may be more applicable to other recursive problems, such as ones to be discussed shortly).&amp;nbsp; For best cache performance, we'd like to try to have nodes near each other processed by the same thread and near to each other in time so that cache hits are optimized.&amp;nbsp; But all of these solutions have been, in effect, randomly assigning nodes to threads.&lt;/p&gt; &lt;p class="MsoNormal"&gt;Once of the nice things about the tree walk example is that it's very simple; there are no pre- or post- processing steps necessary for a node, which means I don't actually need to block at the end of a parent in order to wait for its children as I did in some of the previous examples.&amp;nbsp; The problem also allows me to start processing children of a node before I've finished processing its parent.&amp;nbsp; Many recursive problems are not like that, however.&amp;nbsp; Consider a typical recursive sort, like quick sort:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Quicksort&amp;lt;T&amp;gt;(T[] arr, &lt;span style="color: blue"&gt;int&lt;/span&gt; left, &lt;span style="color: blue"&gt;int&lt;/span&gt; right)&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue"&gt;where&lt;/span&gt; T : &lt;span style="color: #2b91af"&gt;IComparable&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (right &amp;gt; left)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; pivot = Partition(arr, left, right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Quicksort(arr, left, pivot - 1);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Quicksort(arr, pivot + 1, right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;Order here definitely makes a difference.&amp;nbsp; If we think of the Partition step like the execution of the Action in the tree walk example, I'm not able to do the Partition in parallel with the processing of the children, since the processing of the children is dependent on the outcome of the call to Partition.&amp;nbsp; That's a pretty easy problem to workaround of course; I just wouldn't start the children executing asynchronously until after the Partition step is complete.&amp;nbsp; But now consider a recursive sort like merge sort:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Mergesort&amp;lt;T&amp;gt;(T[] arr, &lt;span style="color: blue"&gt;int&lt;/span&gt; left, &lt;span style="color: blue"&gt;int&lt;/span&gt; right)&amp;nbsp;&lt;span style="color: blue"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; where&lt;/span&gt; T : &lt;span style="color: #2b91af"&gt;IComparable&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (right &amp;gt; left)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; mid = (right + left) / 2;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Mergesort(arr, left, mid);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Mergesort(arr, mid + 1, right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Merge(arr, left, mid + 1, right);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;The merge step at a particular node must occur after the recursive calls, which means in a parallel implementation either we'd need to block waiting for the two recursive calls to complete before starting the call to Merge, or we'd have to use a form of continuation-passing style to join on the two merge calls and have their completion start the execution of the merge operation.&amp;nbsp; Either way, this kind of processing with the ThreadPool is incredibly tricky to implement efficiently.&lt;/p&gt; &lt;p class="MsoNormal"&gt;One of our goals when designing Parallel Extensions to the .NET Framework was to make such recursive parallel operations much easier to implement, and much easier to implement efficiently.&lt;/p&gt; &lt;p class="MsoNormal"&gt;Let's start with PLINQ and our tree walk.&amp;nbsp; Taking the Tree&amp;lt;T&amp;gt; iterator we already implemented, processing the tree in parallel is now a cakewalk:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;GetNodes(tree).AsParallel().ForAll(action);&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;Under the covers, this is very much like our implementation where we created several work items, and each of those work items pulled items (under lock) from the&amp;nbsp;enumerator.&amp;nbsp; PLINQ is more efficient, however, and uses varying chunk sizes&amp;nbsp;(rather than always pulling just one element at a time) in an attempt to minimize the number of times the lock must be taken,&amp;nbsp;hopefully reducing contention on the lock.&amp;nbsp; This, of course, as with the similar previous implementation is doing a sequential tree walk but running the actions in parallel.&amp;nbsp; If we actually want&amp;nbsp;to walk the tree in parallel, we can use the Task Parallel Library:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;public&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;{&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.Do(&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; action(tree.Data),&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Process(tree.Left, action),&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Process(tree.Right, action));&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;It's almost scary how simple that is.&amp;nbsp; The Parallel.Do statement potentially runs the three provided operations in parallel, blocking until all three have completed.&amp;nbsp; A really cool thing about this though is that it will attempt to reuse the current thread as much as possible, so we don't run into the same kinds of issues that we had with the ThreadPool where we were blocking a whole slew of ThreadPool threads.&amp;nbsp; The underlying work-stealing nature of the implementation also goes a long way towards helping to address the cache locality issues we previously mentioned.&amp;nbsp; If we want more control, we can dive down below the Parallel class and explicitly use Tasks:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;public&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#000000"&gt;&lt;font size="2"&gt;&lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action)&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;font size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;/span&gt;&lt;font color="#000000"&gt;&lt;font size="2"&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;font size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;/span&gt;&lt;font color="#000000"&gt;&lt;font size="2"&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; t1 = &lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.Create(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;delegate&lt;/span&gt; { Process(tree.Left, action); });&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;font size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;/span&gt;&lt;font color="#000000"&gt;&lt;font size="2"&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; t2 = &lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.Create(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;delegate&lt;/span&gt; { Process(tree.Right, action); });&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(tree.Data);&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;&lt;font size="2"&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;font color="#000000"&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.WaitAll(&lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;[] { t1, t2 });&lt;/font&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/font&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;The same techniques can apply to the quicksort implementation:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;public&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Quicksort&amp;lt;T&amp;gt;(T[] arr, &lt;span style="color: blue"&gt;int&lt;/span&gt; left, &lt;span style="color: blue"&gt;int&lt;/span&gt; right) &lt;span style="color: blue"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; where&lt;/span&gt; T : &lt;span style="color: #2b91af"&gt;IComparable&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (right &amp;gt; left)&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; pivot = Partition(arr, left, right);&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.Do(&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Quicksort(arr, left, pivot - 1),&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;() =&amp;gt; Quicksort(arr, pivot + 1, right));&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;font size="2"&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;as well as to the mergesort implementation:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;public&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Mergesort&amp;lt;T&amp;gt;(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; T[] arr, &lt;span style="color: blue"&gt;int&lt;/span&gt; left, &lt;span style="color: blue"&gt;int&lt;/span&gt; right)&amp;nbsp;&lt;/font&gt;&lt;span style="color: blue"&gt;&lt;font size="2"&gt;where&lt;/font&gt;&lt;/span&gt;&lt;font size="2"&gt; T : &lt;span style="color: #2b91af"&gt;IComparable&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (right &amp;gt; left)&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt; mid = (right + left) / 2;&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.Do(&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Mergesort(arr, left, mid),&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Mergesort(arr, mid + 1, right));&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Merge(arr, left, mid + 1, right);&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;font size="2"&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;I love how simple the parallelization of this code becomes.&amp;nbsp; However, this code still has some issues.&amp;nbsp; There is necessary overhead to an operation like Parallel.Do, which under the covers creates Tasks for the individual operations and waits on those Tasks; that overhead may not be a big deal if the work being done is significant, but for fine-grain concurrency that overhead can end up dominating the computation, potentially causing the parallel implementation to run slower than the sequential implementation.&amp;nbsp; For now, the best way to work around that is to complicate the code slightly with thresholds.&amp;nbsp; The idea behind a threshold is that you introduce enough parallelism to keep the system saturated, but once enough has been expressed, you switch over to a sequential implementation so as to avoid the extra overhead.&amp;nbsp; With the tree walk, using a depth as a threshold might look like this:&lt;/o:p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;span style="font-size: 10pt; color: blue; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;private&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Process&amp;lt;T&amp;gt;(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;Tree&lt;/span&gt;&amp;lt;T&amp;gt; tree, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; action, &lt;span style="color: blue"&gt;int&lt;/span&gt; depth)&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (tree == &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt; (depth &amp;gt; 5)&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;action(tree.Data);&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Left, action, depth + 1);&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Process(tree.Right, action, depth + 1);&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&lt;font size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&lt;font size="2"&gt;else&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.Do(&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; action(tree.Data),&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Process(tree.Left, action, depth + 1),&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;font size="2"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;() =&amp;gt; Process(tree.Right, action, depth + 1));&lt;br&gt;&lt;/font&gt;&lt;/span&gt;&lt;font size="2"&gt;&lt;span style="font-size: 10pt; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: consolas; mso-bidi-font-family: 'Times New Roman'; mso-no-proof: yes"&gt;}&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;I have both a sequential and a parallel implementation here, and I switch from one to the other based on how deep in the tree I am.&amp;nbsp; Depth may not always be the right gating factor to use as a threshold, especially if the tree isn't balanced.&amp;nbsp; We're working through ways to reduce the overhead we currently see for these operations in the early CTP we released in December, and we're testing out some approaches that may eliminate the need to use thresholds in certain cases.&amp;nbsp; For now, though, as you're playing around with the bits, keep thresholds in mind.&amp;nbsp; The same technique could be used with both sorting examples, as well.&lt;/o:p&gt;&lt;/p&gt; &lt;p class="MsoNormal"&gt;&lt;o:p&gt;All in all, parallelism is&amp;nbsp;a very interesting problem when it comes to recursion, and we hope the Parallel Extensions to the .NET Framework go a long way towards making the merging of these two concepts significantly easier.&lt;/o:p&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7357135" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category></item><item><title>LINQ 101, "Parallelism Blockers," and PLINQ</title><link>http://blogs.msdn.com/pfxteam/archive/2007/12/17/6792952.aspx</link><pubDate>Tue, 18 Dec 2007 01:54:15 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6792952</guid><dc:creator>toub</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/6792952.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=6792952</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=6792952</wfw:comment><description>&lt;p&gt;PLINQ is a very cool technology, and I believe it will prove useful for parallelizing operations in a wide range of important scenarios.&amp;nbsp; Moreover, I believe that the programming model it provides will enable a wide-range of developers to easily&amp;nbsp;take advantage of concurrency in their applications.&amp;nbsp; However, one of the risks involved in our providing such a simple programming model is that we don't currently shield developers from all of the possible issues they may run into from using it to parallelize code.&lt;/p&gt; &lt;p&gt;As an example, there is a set of 101 LINQ samples available at &lt;a href="http://msdn2.microsoft.com/aa336746.aspx"&gt;http://msdn2.microsoft.com/aa336746.aspx&lt;/a&gt;.&amp;nbsp; Unfortunately, many of these samples rely on implementation details and behaviors that don't necessarily hold when moving to a parallel model like the one employed by PLINQ.&amp;nbsp; In fact, some of them are dangerous when it comes to PLINQ.&lt;/p&gt; &lt;p&gt;On our team, we've been referring to these kinds of dangers as "parallelism blockers," and they're one of the primary reasons we're not planning to automatically replace all LINQ-to-Objects queries with PLINQ queries, instead supporting the opt-in model available through the AsParallel extension method.&amp;nbsp; We've talked about some of these issues&amp;nbsp;before (see the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e848dc1d-5be3-4941-8705-024bc7f180ba&amp;amp;displaylang=en"&gt;CTP documentation&lt;/a&gt; for a more thorough look at some of these issues), but as a refresher, consider a few examples:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;In your Windows Forms application, you're using LINQ to loop over a long list of UI controls, setting properties on each or searching for one control in particular.&amp;nbsp; You decide to parallelize this with PLINQ.&amp;nbsp; Boom!&amp;nbsp; You get an InvalidOperationException, "Cross-thread operation not valid."&amp;nbsp;In general, properties on UI controls can only be accessed by code running on the thread that created those controls; by using PLINQ, background threads were executing portions of the query, and those portions were accessing controls.  &lt;li&gt;You're using LINQ to search a list containing just a few items for an element with a property set to a specific value.&amp;nbsp; You switch over to PLINQ, and the search takes longer!&amp;nbsp; Why?&amp;nbsp; There is overhead in PLINQ to partitioning the work in order to execute on multiple threads, to merging that work back together in order to produce the output, and so forth.&amp;nbsp; If you're only dealing with a little work, PLINQ likely won't help, and it may make execution slower.&amp;nbsp; (Of course, if it's not taking much time to execute in the first place, one might question the value of parallelism for it.)  &lt;li&gt;You're using LINQ to search a list, and in the process, you're updating a value, such as a count.&amp;nbsp; You switch over to PLINQ, and now your count isn't reflecting the amount of work you've actually done.&amp;nbsp; Why?&amp;nbsp; LINQ was&amp;nbsp;executing the updates sequentially, but PLINQ is executing them in parallel, and thus without synchronization,&amp;nbsp;you have a bad race condition. (NOTE: please, please, please do not modify shared state in LINQ-to-Objects queries)&amp;nbsp;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;The 101 LINQ samples are not good exemplars for PLINQ.&amp;nbsp; Consider the &lt;a href="http://msdn2.microsoft.com/en-us/aa336751.aspx"&gt;Query Execution&lt;/a&gt; category.&amp;nbsp; These samples contain code like:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;int i = 0;&lt;br&gt;var q = from n in numbers select ++i;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;NOOOOOOO!!!!!!!!!!!!!! With PLINQ, those increments to i will potentially happen in parallel, and they won't be atomic.&amp;nbsp; You could fix this by using Interlocked.Increment rather than ++, but then you'd likely destroy your performance.&lt;/p&gt; &lt;p&gt;Luckily, only a few of the 101 samples modify state.&amp;nbsp; But that doesn't mean switching over to PLINQ will produce the same results as LINQ&amp;nbsp;for all of these. Almost all of the 101 samples have the potential to produce different output orderings than the LINQ versions due to lack of order preservation by default (at least in the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e848dc1d-5be3-4941-8705-024bc7f180ba&amp;amp;displaylang=en"&gt;CTP&lt;/a&gt;; we're reconsidering whether that is a good default, so if you have any opinion on the issue, &lt;a href="http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=1986&amp;amp;SiteID=1"&gt;please let us know&lt;/a&gt;).&amp;nbsp; For most of the samples, this doesn’t matter semantically (except for a hypothetical&amp;nbsp;tool that does a straight output to output comparison between LINQ-to-Objects and PLINQ runs); for example,&amp;nbsp;&amp;nbsp;the first sample&amp;nbsp;lists all of the numbers from the array { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 } where the numbers are less than 5, and the second sample&amp;nbsp;lists all of the sold out products from a dynamically generated list of products.&amp;nbsp; However, there are some where (depending on the intended usage) ordering may matter.&amp;nbsp; For example, the eighth sample&amp;nbsp;generates the name of a number in the array (e.g. 5 to “five”); the output ordering may not match up to the input array in this case, and thus while you’re successfully generating all of the relevant outputs,&amp;nbsp; the correlation&amp;nbsp;between input and output&amp;nbsp;is&amp;nbsp;lost (you’d either need to update the query to include in the results the original position, or you’d need to enable order preservation).&amp;nbsp; There are other sample queries that will have this same issue.  &lt;p&gt;Additionally, almost all of the samples deal with very small data sets, and do very little work on each item.&amp;nbsp; It's likely that PLINQ's overhead will dominate in many of these cases, producing slower runs than if LINQ-to-Objects were used.&amp;nbsp; We're spending a lot of time now on PLINQ performance, and we're hoping to see that overhead decrease as much as possible, but even with all of the optimizations we plan to throw at it, it's likely there will still be some queries for which the non-parallel LINQ-to-Objects will still be preferred.&amp;nbsp; That's one place where we need your help.&amp;nbsp; If you have queries that you believe should be executing much faster in parallel than they are, please send them our way; we'd love to analyze them to figure out where bottlenecks may be.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6792952" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category></item></channel></rss>