use Proc::Simple; $| = 1; # debuffer output $max_parallel_jobs = 5; # jobs processed in parallel @running = (); # array of running jobs foreach $job (1..9) { # create pseudo jobs push(@todo, "sleep 3"); } ###################################################################### # while there are jobs to do while($#todo >= 0 || $#running >= 0) { # or started ones are running @running = grep { $_->poll() } @running; # remove finished jobs if($#running + 1 < $max_parallel_jobs && # space free in running? defined($job = pop(@todo))) { # ... and job available print "Starting job '$job' ... "; $proc = Proc::Simple->new(); # new process $proc->start($job) || die "Cannot start job $job"; push(@running, $proc); # include in running list print "STARTED. (Remaining: ", $#todo+1, " Running: ", $#running + 1, ")\n"; next; # proceed without delay } sleep(1); # pause ... and proceed }Cuando se ejecuta, produce esta salida:
$ perl eg/parproc.pl Starting job 'sleep 3' ... STARTED. (Remaining: 8 Running: 1) Starting job 'sleep 3' ... STARTED. (Remaining: 7 Running: 2) Starting job 'sleep 3' ... STARTED. (Remaining: 6 Running: 3) Starting job 'sleep 3' ... STARTED. (Remaining: 5 Running: 4) Starting job 'sleep 3' ... STARTED. (Remaining: 4 Running: 5) Starting job 'sleep 3' ... STARTED. (Remaining: 3 Running: 5) Starting job 'sleep 3' ... STARTED. (Remaining: 2 Running: 5) Starting job 'sleep 3' ... STARTED. (Remaining: 1 Running: 3) Starting job 'sleep 3' ... STARTED. (Remaining: 0 Running: 4)Basándose en Proc::Simple escriba un módulo
Proc::RPC
que de funcionalidades
similares:
Posibles Consideraciones:
start
para un objeto sobre el que hay un proceso ya arrancado?
use vars qw(%EXIT_STATUS %INTERVAL %DESTROYED) ¿Es posible reconvertir las variables globales de paquete a variables léxicas?
start
y añadir un método join
similar a wait
pero que para los procesos hijo
que ejecutan código Perl retorna una estructura de datos Perl. Usando la API de
Proc::Simple::Async
podría ser utilizada así:
$proc = async { map { $_ * $_ } @_ } , 1..3; ... my @r = $proc->join(); # @r es ahora (1, 4, 9)Puede usar Data::Dumper o Storable para serializar los datos retornados. Para ello deberá modificar el método
start
de Proc::Simple:
sub start { my $self = shift; my ($func, @params) = @_; # Reap Zombies automatically $SIG{'CHLD'} = \&THE_REAPER; # Fork a child process $self->{'pid'} = fork(); return 0 unless defined $self->{'pid'}; # return Error if fork failed if($self->{pid} == 0) { # Child if (defined $self->{'redirect_stderr'}) { ... } if (defined $self->{'redirect_stdout'}) { ... } if(ref($func) eq "CODE") { my @r = $func->(@params); # Serialize @r in a temp file using Data::Dumper o Storable u otro ... $self->serialize(@r); exit 0; # Start perl subroutine } else { exec $func, @params; # Start shell process exit 0; # In case something goes wrong } } elsif($self->{'pid'} > 0) { # Parent: ... } else { return 0; # this shouldn't occur } }El método
join
funciona como el método wait
pero lee y evalúa
los contenidos del fichero generado por el proceso hijo.
Es posible que necesite atributos adicionales para guardar el nombre del fichero
mediante el que se comunicarán padre e hijo.
Casiano Rodríguez León