Perl: выполнение нескольких системных процессов и ожидание их завершения - PullRequest
3 голосов
/ 13 февраля 2012

В настоящее время в моем скрипте Perl я выполняю вызов, подобный следующему:

system(" ./long_program1 & ./long_program2 & ./long_program3 & wait ");

Я хотел бы иметь возможность регистрировать, когда каждая из длительных команд выполняется, все еще выполняя их асинхронно.Я знаю, что системный вызов заставляет Perl делать форк, возможно ли что-то подобное?Может ли это быть заменено несколькими вызовами perl fork () и exec ()?

Пожалуйста, помогите мне найти лучшее решение.

Ответы [ 2 ]

6 голосов
/ 13 февраля 2012

Да, определенно. Вы можете отключить дочерний процесс для каждой из выполняемых программ.

Вы можете сделать system() или exec() после разветвления, в зависимости от того, сколько обработки вы хотите, чтобы ваш код Perl выполнял после завершения системного вызова (поскольку exec () очень похожа по функциональности на system(); exit $rc;)

foreach my $i (1, 2, 3) {
    my $pid = fork();
    if ($pid==0) { # child
        exec("./long_program$i");
        die "Exec $i failed: $!\n";
    } elsif (!defined $pid) {
        warn "Fork $i failed: $!\n";
    }
}

1 while wait() >= 0;

Обратите внимание, что если вам нужно сделать много вилок, вам лучше контролировать их с помощью Parallel::ForkManager, а не делать разветвление вручную.

3 голосов
/ 13 февраля 2012

Два варианта:


use IPC::Open3 qw( open3 );

sub launch {
   open(local *CHILD_STDIN, '<', '/dev/null') or die $!;
   return open3('<&CHILD_STDIN', '>&STDOUT', '>&STDERR', @_);
}

my %children;
for my $cmd (@cmds) {
   print "Command $cmd started at ".localtime."\n";
   my $pid = launch($cmd);
   $children{$pid} = $cmd;
}

while (%children) {
   my $pid = wait();
   die $! if $pid < 1;
   my $cmd = delete($children{$pid});
   print "Command $cmd ended at ".localtime." with \$? = $?."\n";
}

Я использую open3, поскольку он короче, чем четный тривиальный fork + exec, и поскольку он не ошибочно приписывает exec ошибки команде, которую вы запускаете, как тривиальный fork + exec.


use threads;

my @threads;
for my $cmd (@cmds) {
   push @threads, async {
      print "Command $cmd started at ".localtime."\n";
      system($cmd);
      print "Command $cmd ended at ".localtime." with \$? = $?."\n";
   };
}

$_->join() for @threads;
...