我有一个Perl脚本,它会分叉许多子进程。我希望有一些功能,如xargs --max-procs=4 --max-args=1
或make -j 4
,其中Perl将保持一定数量的进程运行,直到它失去工作。
很容易说fork 4进程并等待它们全部完成,然后另外四个进行分叉,但是我想保持四个或n个进程同时运行,一完成就会生成一个新进程
Perl中有一种简单的方法来实现这样的进程池吗?
答案 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;
}
}
}