Main Content

How are you getting on?

Archive - Originally posted on "The Horse's Mouth" - 2010-06-13 04:33:57 - Graham Ellis

Have you ever asked someone to do something for you ... a long task, and you would like a progress report? "How are you getting on?" you'll ask ... and they'll give you an update - "I'm 75% of the way through" they'll say or - perhaps even more helpfully - "I'm nearly there, and I have some good results coming through" or "this is taking a long time and isn't looking very productive".

Such feedback can be very valuable - it can allow you to plan your next stage, it may allow you to start working already with intermediate results ... or it can give you the options to say "as it's not working out, let's try something else a bit more productive instead / let's not waste time finishing that job".


Can you say "how are you getting on" to a long running Perl program? If you have written the program accept such requests then, yes, you can!

Perl uses signals in the %SIG hash. There are a whole series of external signals that a program can react to including (for the example I wrote during this week's Perl course) ^C (Control - C) which is in $SIG{INT}.

When you want to set up a signal processor, so that you override the default action, simply put the name of the new handler as a text string into the %SIG hash:
  $SIG{INT} = "hello";
Then - whenever ^C is pressed - the sub called hello will be run.

But before you go off and write a long and exciting piece of code in the sub, remember that you can't control your user - (s)he could press ^C at any subsequent point in your program, and cause the extra piece of code to be run at ANY time; that could be in the middle of a loop, it could be between a series of statements that update a database, or at any other inconvenient time where your data / variables / stack are in a transient state. So - please keep your signal handler routine really simple - I usually just set a global variable to a known value (such as "1" to know I have the signal set); I can then check that variable at the end of an iteration / known points in my code, where I generate a status report based on stable conditions, I reset the flag variable, and carry on.

So:
sub hello {
  $ish = 1;
}


and at the end of my main code loop (after processing the next one of millions of records, perhaps):

if ($ish) {
  print ("$s_x $s_p $s_b\n");
  $ish = 0;
}





But what if I *really* want to abort my program? Well - I've got a little trick. I make a note of the time that ^C is pressed, and if it's pressed twice within 3 seconds, I sense that my user is getting impatient and I exit from the process ;-). Here's my modified sub hello

sub hello {
  $ish = 1;
  $when = time();
  if ($when - $previous < 3) {
    die("Exiting - multiple ^C\n");
    }
  $previous = time();
}


The subject is taught on our Perl for Larger Projects course. And also (where it's appropriate, as it was this week) on private Perl courses run for single organizations.

It's implemented within a complete example - at [here], where I was combining 2 files of over 100 Mbytes each, matching up corresponding records, prior to analyzing them.




Further examples from our course material directories ...

Testing with just a sample of data (truncating the run) [here].

A demonstration with good intermediate user feedback (progress bar with info type) [here].

Asking for intermediate results via signals - [here] and [here]

Illustration - delegates on the Perl course which inspired this example and blog