ewhitt has asked for the wisdom of the Perl Monks concerning the following question:

I have a Perl script to telnet to a list of devices and gather data to put into a MySql database. This script takes a considerable amount of time to complete due to the number of devices. I would appreciate any advice / suggestions on how I could fork child process to parallel this. Also, being able to intercommunicate between the parent and child processes would be helpful (IPC ?). Thanks in advance!
  • Comment on Need advice on how to fork with intercommunication

Replies are listed 'Best First'.
Re: Need advice on how to fork with intercommunication
by clinton (Priest) on Aug 05, 2007 at 10:41 UTC
    Have a look at perlipc. And you could look on CPAN for IPC::Open2 which opens a process for reading and writing.

    Clint

Re: Need advice on how to fork with intercommunication
by NetWallah (Canon) on Aug 05, 2007 at 14:46 UTC
    The THREAD code below should get you started.

    Original attempt by me, but most credit goes to Browseruk.

    #! perl -slw use strict; use threads; use Thread::Queue; $| = 1; #$OUTPUT_AUTOFLUSH our $KIDS ||= 10; our $WORK ||= 500; our $SLEEP||= 5; sub kid { my( $Q ) = shift; my $tid = threads->tid; my $count=0; printf "Kid: %02d started\n", $tid; ## Pick a work item of the queue and process it while( my $work = $Q->dequeue ) { printf "Kid: %02d processing work item '%s'\n", $tid, $work; $count ++; ## Replace the sleep with the code to process teh work items rand > 0.7 and sleep rand( $SLEEP ); } print "kid: $tid ending after processing $count items.\n"; } ## A queue for communications my $Q = new Thread::Queue; ## Start the kids my @kids = map{ threads->create( \&kid, $Q ) } 1 .. $KIDS; ## Wait till they're all up and running sleep 1 until @{[ threads->list ]} == $KIDS; ## Feed the queue with work ## The limit just ensure we don't fill lots of memory for my $workitem ( 1 .. $WORK ) { sleep 1 while $Q->pending > $KIDS *10; print "Queueing work item $workitem"; $Q->enqueue( $workitem ); } ## Tell them to stop $Q->enqueue( (undef) x $KIDS ); ## And wait for them to do so. $_->join for @kids;
    This code has been posted to perlmonks a year or so ago, but I could not find the reference, and it was pretty short anyway.

         "An undefined problem has an infinite number of solutions." - Robert A. Humphrey         "If you're not part of the solution, you're part of the precipitate." - Henry J. Tillman

Re: Need advice on how to fork with intercommunication
by gryphon (Abbot) on Aug 05, 2007 at 14:50 UTC

    Greetings ewhitt,

    Forking is nice, but when I need data back to the parent, I like using threads instead. The communication between source and thread is simple, only once at the end, but it usually does what I need, and it's pretty intuative.

    If you need communication before the end of the thread, you can set that up with shared data structures with threads::shared.

    #!/usr/bin/perl use strict; use warnings; use threads; use IO::File; use Net::SSH 'sshopen2'; use DBI; # username@hostname connect strings my @servers = qw( gryphon@hornet gryphon@kursk gryphon@garfield ); # startup a thread for each server my @threads = map { threads->new( sub { my ($server) = $_[0]; my ( $reader, $writer ) = ( IO::File->new(), IO::File->new +() ); # ssh to the server and run "ls" sshopen2( $server, $reader, $writer, 'ls' ) or die "ssh fa +iled $!"; my @rv; while ( <$reader> ) { chomp(); push @rv, $_; } # return the server name and an array ref of filenames return $server, \@rv; }, $_, ); } (@servers); # usual DBI stuff my $dbh = DBI->connect( 'DBI:mysql:database=DATABASENAME;host=localhost;port=3306', 'USERNAME', 'PASSWORD', { 'RaiseError' => 1, 'AutoCommit' => 1 }, ) or die $DBI::errstr; my $sth = $dbh->prepare('INSERT INTO results (server, filename) VALUES + (?,?)'); # wait for threads to complete; insert data into db foreach (@threads) { my ( $server, $files ) = $_->join(); $sth->execute( $server, $_ ) foreach ( @{ $files } ); } $dbh->disconnect();

    gryphon
    Director Technology, Petfinder.com (Discovery Communications Inc.)
    code('Perl') || die;

Re: Need advice on how to fork with intercommunication
by perrin (Chancellor) on Aug 05, 2007 at 16:31 UTC
    Parallel::ForkManager makes it easy to manage a bunch of jobs in parallel. If you need more communication than you can get from exit codes, sharing through your MySQL database is a pretty simple way to do it. It has more overhead than local socket techniques, but is easier to get started with and less error-prone.