We were trying to speed up a process where we had to call a system command about 40 times, and process the output. My first try at a sample program had the
close and remove() lines below swapped, and this caused badness in that some of the processes were never read from (it seems to be bad to remove a closed filehandle from an IO::Select object). Also, after
carefully reading the
IO::Select documentation, I saw that you could pass an arrayref to the add() method (never noticed that before!), thereby saving some extra info with the handle in the select object, which came in handy. The below is my resulting "Hello World" example:
#!/usr/bin/perl
use warnings;
use strict;
use IO::Select;
# Number of simultaneous processes
my $n = 5;
# List of things to process
my @p = (1..20);
my $sel = IO::Select->new();
for my $pr (splice @p, 0, $n) {
start_ps($sel, $pr);
}
my $cnt = 1;
while ( my @ready = $sel->can_read() ) {
for my $h (@ready) {
local $_;
my ($fh, $i) = @$h;
while (<$fh>) {
print "$i: $_";
}
# Remove, then close!!!
$sel->remove($fh);
close $fh;
start_ps($sel, shift(@p)) if @p;
$cnt++;
}
print "-------------\n";
}
sub start_ps {
my ($t, $p) = @_;
my $pid = open(my $fh, "-|");
die "Can't fork: $!" unless defined $pid;
unless ($pid) {
my @cmd = qw(/bin/echo Hello World);
exec @cmd;
die "Could not exec @cmd: $!";
}
$t->add([$fh, $p]);
}