“Task parallelism (also known as function parallelism and control parallelism) is a form of parallelization of computer code across multiple processors in parallel computing environments. Task parallelism focuses on distributing execution processes (threads) across different parallel computing nodes. It contrasts to data parallelism as another form of parallelism.” – Wikipedia – Task Parallelism
This post is a part of a series on WF, Parallelism and Threading
- Windows Workflow Foundation (WF4) Activities and Threads
- The Workflow Parallel Activity and Task Parallelism
- Windows Workflow (WF4) Task Parallelism with Sequences
- Windows Workflow Foundation (WF4) ParallelFor Activity
- Windows Workflow Foundation (WF4) - Parallel and ParallelFor Behavior (sample)
Can you achieve Task Parallelism with Windows Workflow Foundation?
Yes… yes you can. I know, in my previous post (Windows Workflow Foundation (WF4) Activities and Threads) I said that every workflow instance is single threaded. Within each workflow there is one and only one thread servicing activities. There are no activities for creating threads or waiting on threads etc. However, Windows Workflow Foundation (WF4) is well suited to Task Parallelism because
Each workflow invoked with WorkflowApplication or a Workflow Service or can be though of as a Task which will run on a different thread
Multiple Asynchronous Activities can be invoked at the same time
Asynchronous Activities can queue work to another thread using a Task
Parallel with Synchronous Activities
Each workflow you create is a task which is made up of activities. As the workflow moves through the activities it will process each one in the order that the activities are scheduled by the parent activity. Some activities allow you to schedule multiple child activities at a time - Parallel, ParalleFor, Pick and State are all examples of this. Here you see that the Parallel activity has scheduled three child activities which are pushed onto a “Stack” of activities (actually it is a strange hybrid of Queue / Stack we call a Quack).
Note: The activities are scheduled in reverse order starting with the last activity (on the right)
If the child activities are synchronous (like CodeActivity<T>) then the process is very simple. The Workflow Runtime grabs the first activity on the stack and the calls the Activity.Execute() method. Each activity then begins in the Executing state and as it completes moves to the Closed state. In the following diagram the Parallel has already invoked and closed activity 1 (which is now removed from the stack) and is now executing activity 2. Activity 3 is already scheduled and is waiting it’s turn to rise to the top of the stack.
If your Parallel activity contains only synchronous activities then it is no different than a Sequence composed of the same activities.
The tracking data would show that Activity 1 started and completed, followed by activity 2 and activity 3 in exactly the same way.
Parallel with Asynchronous Activities
To truly realize Task Parallelism with the Parallel activity you must create an activity which is asynchronous (such as an AsyncCodeActivity<T> or contains at least one child activity that is asynchronous such as a Send or Delay activity). In the following diagram you see a Parallel where the child activity is configured to schedule a Delay activity with a duration of 1 millisecond. The Delay activity creates a bookmark and returns from the Activity.Execute method. When an activity returns from the Execute() method with an outstanding bookmark it remains in the Executing state. Then the Workflow Runtime then pops the next activity off of the scheduled stack and starts executing that one.
In the following diagram, the Parallel has already started executing child activities 1 and 2 which have both created bookmarks so they are still executing. Activity 3 is on top of the stack so it will be the next activity to execute.
After all three child activities have started executing and set bookmarks if the scheduled stack is empty the workflow cannot continue to do work because there are no scheduled child activities so it becomes idle. Depending upon the settings of the host environment the workflow may now be persisted and possibly even unloaded.
In my simple example, I have used a Delay activity to simulate long running work, but you can imagine that the work could be any kind of long running process or I/O operation such as invoking a web service, updating a database or reading/writing a file. Because these operations take a long time to complete placing asynchronous activities into a parallel allows them to all execute concurrently which provides us with Task Parallelism.
At some later point when the I/O completes or the Delay duration is met the asynchronous activities will resume. When the activities do complete their work it can be in any order. In this example, activity 2 has already resumed and completed, activity 1 is resuming and activity 3 is still pending.
Windows Workflow Foundation is very capable of Task Parallelism and is well suited to doing complex work which requires a great deal of coordination. The Parallel Activity makes it easy to do several asynchronous tasks concurrently and to wait until all (or some) of them complete before continuing to the next activity.
In my next post on Task Parallelism we will consider how the Parallel Activity behaves when used with the Sequence activity.