Analizo
view release on metacpan or search on metacpan
lib/Analizo/Batch/Runner/Parallel.pm view on Meta::CPAN
package Analizo::Batch::Runner::Parallel;
use strict;
use warnings;
use ZMQ::FFI qw(ZMQ_PUSH ZMQ_PULL ZMQ_REQ ZMQ_REP);
use YAML::XS;
use parent qw( Analizo::Batch::Runner );
$YAML::XS::LoadBlessed = 1;
$YAML::XS::LoadCode = 1;
$YAML::XS::DumpCode = 1;
sub new {
my ($class, $parallelism) = @_;
$parallelism ||= 2;
$class->SUPER::new(parallelism => $parallelism);
}
sub parallelism {
my ($self) = @_;
return $self->{parallelism};
}
sub actually_run {
my ($self, $batch, $output) = @_;
$self->start_workers();
$self->coordinate_workers($batch, $output);
$self->wait_for_workers();
}
sub _socket_spec {
my ($name, $ppid) = @_;
return "ipc:///tmp/.analizo-$name-$ppid";
}
sub start_workers {
my ($self) = @_;
$self->{workers} = [];
my $n = $self->parallelism();
my $ppid = $$;
for my $i (1..$n) {
my $pid = fork();
if ($pid) {
# on parent
push(@{$self->{workers}}, $pid);
} else {
# on child
$0 = '[analizo worker]';
worker($ppid);
exit();
}
}
my $distributor_pid = fork();
if ($distributor_pid) {
push(@{$self->{workers}}, $distributor_pid);
} else {
$0 = '[analizo queue]';
distributor($ppid, $n);
exit();
}
}
sub wait_for_workers {
my ($self) = @_;
for my $pid (@{$self->{workers}}) {
waitpid($pid, 0);
}
}
sub coordinate_workers {
my ($self, $batch, $output) = @_;
my $context = ZMQ::FFI->new();
my $queue = $context->socket(ZMQ_PUSH);
$queue->bind(_socket_spec('queue', $$));
( run in 2.927 seconds using v1.01-cache-2.11-cpan-9581c071862 )