http://www.perlmonks.org?node_id=156507

MadMax has asked for the wisdom of the Perl Monks concerning the following question: (subroutines)

Is there a way to run a sub-routine in a non-linear fashion? For example, I need to ping to 100 ip's to check the connectivity of my entire system.

(linear method) I currently ping each ip individually "one at a time" and wait for the entire list to complete. This can take a while if I set a 2 second timeout on the ping.

(non-linear method) What I would rather do is use a subroutine to ping each ip "in the background (in unix: a command followed by a '&')" and then wait until each of the ping subroutines reports back (or an appropriate amount of time) and compile the results.

Originally posted as a Categorized Question.

Replies are listed 'Best First'.
Re: Running subroutines asynchronously
by NetWallah (Canon) on Oct 03, 2005 at 04:31 UTC
    Here is some Thread::Queue based code that demonstrates another way to resolve the parallel-ping problem.

    You can use it to model generic parallel processing subroutines where you have one work queue, and multiple workers. The results generated by the workers is fed back into a single queue, that is read by the main process.

      Side note comment: a cheap albeit admittedly much more limited alternative to gain some parallelization through open can be found here.
Re: Running subroutines asynchronously
by crazyinsomniac (Prior) on Apr 04, 2002 at 08:01 UTC
    use Proc::Forkfunc;
    use strict;
    
    $|++; # autoflush/unbuffer
    
    my @child_args = qw(1 2 );
    
    forkfunc(\&child_func, @child_args);
    forkfunc(\&child_func, 3);
    forkfunc(\&child_func, 4);
    forkfunc(\&child_func, 5);
    
    sub child_func {
        # sleep for rand(3)*rand(3)
        select undef, undef, undef,  rand(3) * rand(3);
    
        print shift(@_);
        print "\n";
    }
    Proc::Forkfunc has the annoying habit of printing to STDERR "call to child returned", but it's not a complex module, and if you crack it open (look at the source), you can easily figure out what's goin on. You should also take a look at perlfork. This will work for most systems, but remember, forking is experimental on Win32 machines, and is not available before v5.6, but there is an alternative, Win32::Process.
Re: Running subroutines asynchronously
by ehdonhon (Curate) on Apr 04, 2002 at 03:20 UTC
Re: Running subroutines asynchronously
by tachyon (Chancellor) on Apr 05, 2002 at 00:43 UTC

    Sounds like a job for fork(). Fork a stack of kids to do the pinging and waiting in parallel.

    Check out Non-linear sub-routine launching for more details.

    #!/usr/bin/perl -w use strict; use POSIX ":sys_wait_h"; $|++; my @hosts = qw( www.perlmonks.com www.perl.com www.netscape.com ); my (@pids, $count); for my $host(@hosts) { sleep 1; # this limits to 1 kid per second, not actually required $count++; my $pid = fork(); push @pids , $pid; die "Fork failed\n" unless defined $pid; next if $pid; # get parent to reiterate and fork more kids my $reply = `ping -n 1 $host`; # get kids pinging, single ping print "I am child $count, pinged $host\n$reply\n\n"; exit; # kill child } # wait for kids to finish, no zombies on us my $kids; do { $kids = waitpid(-1,&WNOHANG); } until $kids == -1; print "Spawned $count kids, waited on @pids\nAll done!";