perl进程队列

时间:2010-08-06 14:35:03

标签: perl multiprocessing

我有一个Perl脚本,它会分叉许多子进程。我希望有一些功能,如xargs --max-procs=4 --max-args=1make -j 4,其中Perl将保持一定数量的进程运行,直到它失去工作。

很容易说fork 4进程并等待它们全部完成,然后另外四个进行分叉,但是我想保持四个或n个进程同时运行,一完成就会生成一个新进程

Perl中有一种简单的方法来实现这样的进程池吗?

3 个答案:

答案 0 :(得分:11)

Forks::Super可以处理此要求。

use Forks::Super MAX_PROC => 5, ON_BUSY => [ block | queue ];

fork()的调用可能会阻塞,直到活动子进程数低于5,或者您可以将其他参数传递给fork调用,并且要执行的任务可以排队:

fork { sub => sub { ... task to run in subprocess ... } }

当一个子进程完成时,队列中的另一个作业将启动。

(我是本单元的作者)。

答案 1 :(得分:6)

查看Parallel::ForkManager - 它完成了您描述的大部分内容。您可以设置最大进程数,并且一旦完成,回调函数就可以启动一个新子进程(只要有工作要做)。

答案 2 :(得分:2)

虽然我几乎总是使用CPAN模块,或者用奇妙的AnyEvent模块编写一些内容,但我认为了解这些内容如何工作非常重要。这是一个除了perl之外没有依赖关系的例子。同样的方法也可以用C编写而不会有太多麻烦。

#!/usr/bin/env perl

use strict;

## run a function in a forked process
sub background (&) {
  my $code = shift;

  my $pid = fork;
  if ($pid) {
    return $pid;
  } elsif ($pid == 0) {
    $code->();
    exit;
  } else{
    die "cant fork: $!"
  }
}

my @work = ('sleep 30') x 8;
my %pids = ();
for (1..4) {
  my $w = shift @work;
  my $pid = background {
    exec $w;
  };
  $pids{$pid} = $w; 
}

while (my $pid = waitpid(-1,0)) {
  if ($?) {
    if ($? & 127) {
      warn "child died with signal " . ($? & 127);
    } else {
      warn "chiled exited with value " . ($? >> 8);
    }

    ## redo work that died or got killed
    my $npid = background {
      exec $pids{$pid};
    };
    $pids{$npid} = delete $pids{$pid};
  } else {
    delete $pids{$pid};

    ## send more work if there is any
    if (my $w = shift @work) {
      my $pid = background {
        exec shift @work;
      };
      $pids{$pid} = $w;
    }
  }
}