Many hands make light work


The last posting on collections, whilst being a bit on the long side was fairly straightforward to follow. Today’s posting is a little more, umm, challenging … The reason is I really want to show you what’s possible in the .NET Framework 4.0 that means you will be able to make your apps scream along on modern, multi-cored processors with minimal effort.

First off, a little theory. Most programming languages provide the ability to execute external functionality through transferring control to code referenced by a pointer. Modern COBOL in fact uses procedure pointers to provide this functionality (it just wasn’t possible in OS/VS COBOL). The problem with this type of transfer of control is that it is not safe: you can’t guarantee that you are passing the correct parameters or will receive the correct data back. The .NET Framework gets around this problem through the use of Delegates. Delegates are a type safe way of invoking functionality. This invocation may be synchronous or asynchronous. A delegate describes what some function looks like without defining it. In order to use a delegate you must go through three steps:

  1. define the delegate or method signature
  2. instantiate the delegate
  3. invoke the delegate

In this particular posting, I have to admit we’ll be going through this (to use the vernacular), arse about face. The only reason for this is I had a bit of fun writing this particular bit of code and I want to get it out there and then get on to explaining delegates better!

In this example we’re going to use a generic delegate already defined in the .NET Framework: System.Action. If we look at the code for the new DirectoryCollection (nothing else was modified), I’ve highlighted the new code and commented out the replaced code: 

class-id DirectoryUtility.DirectoryCollection  
  inherits type System.Collections.Generic.List[type System.IO.FileInfo].

working-storage section.

01  DirectoryName   string as "DirectoryName" public property with no set.
   
method-id New.
local-storage section.

01  dirInfo         type System.IO.DirectoryInfo.
01  fiArray         type System.IO.FileInfo[].
01  fInfo           type System.IO.FileInfo.
    
procedure division using by value directoryName as string.

    Set DirectoryName to directoryName.
    Set dirInfo to new type System.IO.DirectoryInfo(DirectoryName).          
    Set fiArray to dirInfo::GetFiles("*.cbl").
    
    Perform varying fInfo through fiArray
        Invoke self::Add(fInfo)
    End-Perform.

    goback.
end method.

method-id Compile public.

local-storage section.

*>01  fInfo           type System.IO.FileInfo.
01 actionDelegate   type System.Action[type System.IO.FileInfo].     
       
procedure division.

    Invoke type DirectoryUtility.CobolUtilities::Initialise().
*>   Perform varying fInfo through self
*>       Invoke type DirectoryUtility.CobolUtilities::
*>                   CompileProgram(
*>                       fInfo::FullName, 
*>                       fInfo::DirectoryName
*>                                 )
*>   End-Perform.          

Set actionDelegate to new type Action[type System.IO.FileInfo]
(
delegate using fInfo as type
System.IO.FileInfo
invoke type DirectoryUtility.CobolUtilities::

                            CompileProgram(
                                fInfo::FullName, 
                                fInfo::DirectoryName
                                          )
             end-delegate
        ).       
 
    Invoke type System.Threading.Tasks.Parallel::ForEach
                    (self, actionDelegate).
                     
    goback.
    
end method.

end class.

Firstly, I define actionDelegate as a System.Action generic delegate of type System.IO.FileInfo. Then I instantiate actionDelegate using the anonymous delegate syntax (the delegate … end-delegate stuff) with the identical code that had been wrapped previously in the Perform varying … End-Perform. I can then invoke the delegate for each System.IO.FileInfo object within the collection using System.Threading.Tasks.Parallel’s ForEach method. This function, part of the Task Parallel Library of .NET Framework 4.0 knows about your hardware and is  able to schedule processing of tasks in parallel to optimise the usage of that hardware. So is it worth it? You be the judge:

 

SNAGHTMLba62613

Look at the duration there: 14 minutes 22 seconds (or 862 seconds). Sequentially, this took 46 minutes 18 seconds (or 2778 seconds). That’s a reduction in duration of 69%. This program was running whilst I was editing this posting, had several Internet Explorer windows open, Outlook, Visual Studio and lord knows what else, at no time losing responsiveness.  Look at Task Manager for some of those programs below. Notice the number of compiler processes running at the top …

image

 

Now I do admit my laptop is a quad core, but that’s what those cores are for, isn’t it? The System.Threading.Tasks functionality drives those cores hard without overwhelming them. Check out the Performance tab on Task Manager during the running of the program. Notice the workout each CPU is getting.

image

The program isn’t production strength and could definitely do with some polishing (the displays come out at a different point to the compilation output due to the fact that the threads are running concurrently), but still not bad for an hour’s work (in total – including the previous post’s code)…

The code can be found here:

http://cid-29bd479bafba9591.office.live.com/embedicon.aspx/COBOL%20School/Multi-threaded%20Cobol%20Directory%20Collection.zip

Advertisements

One response to this post.

  1. […] This post was mentioned on Twitter by Alexander J Turner, Michael Burgun. Michael Burgun said: Many hands make light work: https://burgun.wordpress.com/2011/02/23/many-hands-make-light-work/ […]

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: