Firefly
Firefly

Reputation: 459

Measure the execution time of a function call in Perl

Is it possible to execute staff only if the previous function is not over yet and the time is over Something like:

my $timeout = 10; # seconds
sub get_entities {
    # do staff ...
}
get_entities();

if (time == $timeout and get_entities is not over yet) {
    # do staff...
}

Upvotes: 0

Views: 2800

Answers (2)

Sobrique
Sobrique

Reputation: 53508

Your edit made the question considerably more complicated.

As I'm sure you'll know - as a standard, perl runs sequentially - if a command takes 25s, then the rest of the code just waits until it's ready.

But sometimes, you want to build in a timeout yourself for various reasons. There's a number of ways you can do this:

alarm and a signal handler

#!/usr/bin/env perl

use strict;
use warnings; 

$SIG{'ALRM'} = \&handle_alarm; 

my $we_are_snoozing = 1;

sub handle_alarm {

   print "Caught SIGALRM\n";
   $we_are_snoozing = 0;
}

sub have_a_snooze {
   while ( $we_are_snoozing ) {
       print "Zzzz\n";
       sleep 10;
   }
}


alarm 25;
have_a_snooze;
print "Done\n";

You're limited in what you can do inside your handler - keep it minimal. But alarm generates a SIGALRM (which can also be generated by kill) and the process can trap and handle it.

threads

Threads allow you to spin off part of your code to run in parallel or asynchronously. This is handy for both resource usage, but also when you're faced with a thing that's not worth waiting indefinitely for.

#!/usr/bin/env perl

use strict;
use warnings; 

use threads; 
use threads::shared;

my $we_are_snoozing : shared;
$we_are_snoozing = 1; 

sub have_a_snooze {
   while ( $we_are_snoozing ) {
       print "Zzzz\n";
       sleep 10;
   }
}


my $thr = threads -> create (\&have_a_snooze);

sleep 5;

if ($thr -> is_joinable) { 
   print "Thread exited normally\n";
   $thr -> join;
 }
 else {
    print "Thread still running, detaching it\n"; 
    $we_are_snoozing = 0;
    $thr -> detach;
}

IO::Socket and can_read

One of the more common reasons for wanting a timeout, is simply waiting for IO.

This is quite easy to handle with IO::Socket and a timeout:

#!/usr/bin/env perl
use strict;
use warnings;

my $pid = open ( my $input, '-|', "some_command" );
my $select = IO::Select -> new ( $input ); 
while ( $select -> can_read(10) ) { 
  my $line = <$input>;
  print $line; 
}

This will timeout 10s after the last result, not the first. But that may be useful too.

Upvotes: 4

Dave Cross
Dave Cross

Reputation: 69314

Have you tried this?

my $start = time;
get_entities();
my $duration = time - $start;

Or were you looking for something more sophisticated?

Upvotes: 6

Related Questions