In my previous posts I’ve been arguing that you can implement Task Parallelism with Windows Workflow Foundation (WF4). 

This post is a part of a series on WF, Parallelism and Threading

  1. Windows Workflow Foundation (WF4) Activities and Threads
  2. The Workflow Parallel Activity and Task Parallelism
  3. Windows Workflow (WF4) Task Parallelism with Sequences
  4. Windows Workflow Foundation (WF4) ParallelFor Activity
  5. Windows Workflow Foundation (WF4) - Parallel and ParallelFor Behavior (sample)

One of the most common scenarios for Task Parallelism is when you have a Task that you must perform for each element of a collection. Suppose you have a collection of names, and you want to write each name to the console.  The ParallelFor activity makes it simple to do this work.

image

If I have three names in my collection, the ParallelFor activity will start by scheduling the Body for each name in the list starting with the last name first

image

Then the Workflow Runtime will process each Body activity as it comes to the top of the stack.  Each one will execute until they complete.  If they are become idle, the next one in the stack will begin executing.  In the following diagram, all three names have started processing, the bookmark for Sam is now resuming so it can complete.

image

When I run this test, the output is

[76] Start Chu
[76] Chu Idle
[76] Start Tina
[76] Tina Idle
[76] Start Sam
[76] Sam Idle
[76] End Chu
[76] End Tina
[76] End Sam

Nested ParallelFor

What if we had a more complex type?  Instead of just a name, now suppose I have a Contact which also has a list of friends.

   1: public class Contact
   2: {
   3:     public Contact()
   4:     {
   5:         this.Friends = new List<string>();
   6:     }
   7:  
   8:     public List<string> Friends { get; private set; }
   9:  
  10:     public string Name { get; set; }
  11: }

Now suppose my task is to write each name as before using a delay to show the async behavior but then I will also write each friend’s name using the synchronous behavior.

image

Each name gets scheduled as before and then the task will process each contact’s friends

[69] Start Chu
[69] Chu Idle
[70] Start Tina
[70] Tina Idle
[70] Start Sam
[70] Sam Idle
[69] End Chu
Friends of Chu
[51] Chu friend Michael
[51] Chu friend Gary
[51] Chu friend Leon
[51] Chu friend Hani
[70] End Tina
Friends of Tina
[52] Tina friend Sarah
[52] Tina friend George
[70] Tina friend Nick
[70] End Sam
Friends of Sam
[69] Sam friend David
[69] Sam friend Alice

Summary

We could go on and on with this.  A ParallelFor with a ParallelFor and a Parallel inside of it etc.  I think by now you get the idea of how Task Parallelism can be achieved with Windows Workflow Foundation.

Sure, we use one thread to run your workflow.  Don’t let that worry you.  In fact, it is exactly the right thing to do.  Window Workflow Foundation does by nature what very efficient multi-threaded programs do.  They schedule (enqueue) tasks and then process the tasks with a thread from the thread pool.

By using a single thread in your workflow we avoid nasty side effects of threading such as race conditions and the need for synchronization primitives making it possible for even beginners to write workflows that will behave very nicely on multi-processor / multi-core systems.

Happy Coding!

Ron Jacobs
http://blogs.msdn.com/rjacobs
Twitter: @ronljacobs http://twitter.com/ronljacobs