The MacView

Virtual Instrumentation from a Mac perspective

Thursday, April 01, 2010

Threading using Queues

I found something unexpected today. I had written a VI to generate a report of the linkages between files in the LabVIEW distribution. It was a quick and dirty VI that basically did the following:

1. Find all the VIs, Controls, Classes, Libraries, Projects, etc. in the LabVIEW distribution

2. Read the linkage information from the file

3. Write out a report on the file

Here is a simplified version of what I was doing:

With this method, LabVIEW pegged the CPU at 100%. Well, LabVIEW pegged one of my four CPUs at 100%. That's great because I can do other things, but I'd like this to finish as soon as possible. So I broke the three tasks into three separate loops that communicate through Queues. Below is the code:

My code went from using 100% CPU to 250% to 270% CPU.

To use Queues to increase your threading, you need to be able to break up your code into tasks that can be run simultaneously. Usually if you are waiting for I/O, that is a good task. Here I have three disk operations (Directory Listing, Read From File, Write To File). It turns out the slowest of these is reading the linkage information from the file. So much so that the Queue of Paths stays full and the Queue of information to write remains close to empty. To help improve performance in a case like this, you can set a maximum Queue size (on the Path Queue in my case). I set the maximum size to 1,000 Paths. So the Read Link loop would always have no more than 1,000 Paths waiting for it. When it takes a Path from the Queue, the Directory Listing loop wakes up and puts another Path in the Queue.

One trick is to figure out how to end the loops. With many of the LabVIEW APIs, you can loop until the Read operation returns an error, and in the Write loop, just close the reference. With Queues that doesn't work because you may close the Queue with data still in it (1,000 Paths, for instance). So instead we send some invalid data that we would not otherwise send (Not A Path in the Path Queue instance). When each loop finishes stuffing data into the Queue, it puts an invalid element in the Queue. Then the loops that read from the Queue know to stop when they see invalid data.

I hope using this can improve the performance of your VIs. If you have any questions or improvements, please leave them in the comments.

Labels: , , , , ,

The views expressed on this website/weblog are mine alone and do not necessarily reflect the views of my employer.