The dispatcher is the object that holds a thread pool. The dispatcher queue holds the list of pending delegates that can be executed immediately and are waiting for a thread to become available.

The ParallelDirectorySizeRecursive method calculates the size of the directory by enqueuing tasks in the dispatcher queue. When the computation is complete, it posts the result to the outputPort.A port is essentially two queues. The first queue holds (data) messages and the second queue holds methods interested in processing these messages. The WaitOnPort is an extension method (not part of the CCR) that blocks until a message is received and returns the received value.

The asynchronous recursive implementation enqueues the following tasks:

Task that sums the total file size in the directory. This task is scheduled for immediate execution. Once it completes, it posts the result to inputPort.

Each recursive call enqueues a task that posts the sub directory size to inputPort. The recursive call is invoked subDirectories.Length times.

Task that sums all of the results in inputPort and posts it to outputPort.This task is scheduled for execution once inputPort has subDirectories.Length+1 values in it (which means file size and recursive sub directory size computation has completed).

If you are new to anonymous methods (delegates), note that these tasks run on a separate thread, but they still have access to local variables (such as directory and subDirSize). What actually happens is that they receive a copy that can be used in their thread. This makes the code much shorter.

Error Handling

We would like the recursion to recover from UnauthorizedAccessException(s). The simple recursive implementation receives a Collection<Exception> which is used to collect caught exceptions. All recursive calls receive the same collection object:

Similarly the parallel recursion receives a Port<exception> object (see outputPort.P1 below). The same exception port object is passed to all recursive calls.One caveat here - the method has to post a zero result to the outputPort (see outputPort.P0 below) even when an error occurs. This is needed since the "Sum" task is not listening on the exception port, and it keeps waiting for exactly subDirectories.Length + 1 results.