Nov
04

Worker pool – a design pattern for parallel task execution in LabVIEW

by Tomi Maila, Nov 4, 2009 at 2:00 pm
1 Star2 Stars3 Stars4 Stars5 Stars (6 votes, average: 5.00 out of 5)
Loading ... Loading ...

Creating parallel code in LabVIEW is simple; simply place parallel tasks parallel on VI block diagram and the tasks are executed in parallel. However this design doesn’t bend to use cases when the number of parallel tasks is not known at development time but needs to be specified at runtime.  In this post I present simple design pattern for parallel code execution based on recursion. In my next post I study the recursive concurrency in more detail.

Let’s consider first the dilemma to which this design pattern is a solution. You want to execute a number of different tasks in parallel. The tasks that need to be executed are not known at development time. Alternatively the tasks are known at the development time but the required level of parallelism is not known. As an example, consider a complicated data analysis task that can be massively parallelized. However, you may want to optimize the parallelization at runtime to meet the number of processors availble in the workstation. As an other example consider a server serving a number of network connections. Each connection is represented by a listener task on your server application. You can only know the number of listeners requires at runtime.

A common design to execute parallel tasks at runtime is to first open a VI reference using  application server, then prepare the VI for execution and finally use the VI server Run VI method to execute the VI. As there is not dataflow dependency between the parallelly executing VI and the calling code, passing the results and possible errors from the executing code requires external mechanisms.

The worker pool design pattern I am introducing in this post is based on VI recursion and command design pattern. I present two variations of the design pattern, a dataflow based worker pool and queue based worker pool. For both variations of the pattern, the tasks are represented by a command design pattern. That is, each type of a task is represented by a class that is a child (descendant) class of Command class. Each of these classes implement a execute method of the command class that actually executes the task. A typical task class contains 1) create method for initializing the task parameters, 2) an execute method for performing the task and 3) methods for querying the results of the executed task. The initialized commands are passed for the worker pool, that then executed the execute method of each task.

The dataflow based worker pool is suitable for use cases where the tasks can be completely specified before parallel execution is required and the results of the executions are not required until all parallel tasks have finished. The idea is very simple, pass an array of Command objects to a worker pool VI. The worker pool VI then removes one task from the array and executes it. In parallel to this, worker pool calls to itself recursively to execute the rest of the tasks. The worker pool VI needs to be re-entrant of type share clones between instances. All the tasks in the array are this way executed in parallel and there are no development time limitations to the number of workers that can execute in parallel. The results of the tasks are returned in dataflow manner. The image below illustrates an implementation of dataflow worker pool pattern.

Dataflow worker pool

Dataflow worker pool block diagram

The queue-based worker pool is suitable for use cases where the tasks need to be created dynamically during the execution of the application and where the results of the tasks need to be processed as soon as the tasks have finished executing. The queue-based worker pool pattern combines the producer-consumer design pattern with the command design pattern. The idea is similar to the dataflow worker pool. However unlike in the dataflow worker pool, a queue of commands and a queue for results are passed for the worker pool. The worker pool reads a command from the commands queue, executes it and writes the result to the results queue. In parallel to this, worker pool executes itself recursively, as in dataflow worker pool pattern. The commands are enqueued to the command queue and the results are dequeued from the result queue in some parallel processes. When the command queue is closed, the worker pool finishes executing the tasks in progress and returns.

Queue based worker pool block diagram

Queue based worker pool block diagram

There can be multiple variations of these base patterns. The tasks can be passed via command queue but the results returned via dataflow output terminal. A worker pool can combine a sequential loop based task execution with presented recursive parallel execution to allow reusing workers that are currently idle. It would be a good design to encapsulate the worker pool to a class that implements general worker pool interface.

I have attached a simple example project illustrating the usage of the presented design patterns. Please sign-up to ExpressionFlow to download the project. The example project requires LabVIEW 2009 development environment.


Worker Pool.zip 1.1

224.12 KB
You must be logged in to download this item!
Please login or register now.

Print This Post Print This Post

5 Comments

Make A Comment

Comments RSS Feed   TrackBack URL

Leave a comment

You must be logged in to post a comment.

Download Full Movie Online Bridget Jones's Diary download movie Perfect Parents download movie The Invisible download movie Once download movie Cypher download movie Night Skies download movie Spaceballs download movie Gotti download movie Little Murders download movie Nuns of saint archangel, the download movie Krull download movie Family business download movie Prague duet download movie Wake in fright download movie Robin hood download movie Are you being served download movie