我想做一些并行子进程,但是,所有子进程都已完成,然后我只想启动/继续我的父进程。下面是我的示例代码
foreach ('abc.gz','efg.gz','123.gz','xyz.gz')
{
my $pid = fork;
if ($pid == 0) {
exec("tar -xvf $_");
exit 0;
}
}
wait();
`tar -xvf 'parent.gz'`;
在上面的代码中我想在所有子进程提取结束时提取我的“parent.gz”。但是,它正在子进程的中间提取“parent.gz”。所以,请帮助我。
我只能使用perl核心模块,我的perl版本是v5.10.1
由于 Baski
答案 0 :(得分:3)
这里的问题是 - fork
是关于并行处理的,而wait()
来电并不一定等待所有孩子。确实 - 它只等待第一个,并返回pid。请参阅:perldoc wait
我也会指出 - 你可能不会因为在这里分叉而获得太多收益。 fork
并没有让任何事情变得更快 - 它只会提升一些争用块,并允许您并行使用某些资源(cpus)。你的限制因素是可能而不是CPU(可能是因为减压 - 如果你没有做.gz
个文件,那几乎肯定不会) 。但是磁盘通常是系统中最慢的东西,并且可能可能是你的限制因素。通过平行书写,你不会因此获得很快的速度。
另外:您可能希望在tar命令中使用z
标志,因为它们看起来像gzip
个压缩文件(我假设它们也是tarball,因为这不会如果他们没有意义的话。
到目前为止,最简单的方法是Parallel::ForkManager
模块:
use strict;
use warnings;
use Parallel::ForkManager;
my $manager = Parallel::ForkManager -> new ( 10 );
foreach ('abc.gz','efg.gz','123.gz','xyz.gz')
{
$manager -> start and next;
exec("tar -xvf $_");
exit 0; #probably redundant, because exec will mean it's not called.
$manager -> finish;
}
$manager -> wait_all_children
`tar -xvf 'parent.gz'`;
但是,如果你没有使用额外的模块(实际上这是一个经常出现的限制,并且是一个很难应用的限制)。您可以简单地拨打wait
3次,但我不喜欢这种解决方案,因为它可能被其他隐含的叉子绊倒。
所以我建议改用waitpid()
。
my @pids;
foreach ('abc.gz','efg.gz','123.gz','xyz.gz')
{
my $pid = fork;
if ($pid == 0) {
exec("tar -xvf $_");
exit 0;
}
else {
push ( @pids, $pid );
}
}
foreach my $pid ( @pids ) {
print "Waiting for pid $pid\n";
waitpid ( $pid, 0 );
}
`tar -xvf 'parent.gz'`;
或者,作为收获所有孩子的一种方式:
my $result = wait();
while ( $result >= 0 ) {
$result = wait();
}
wait
如果没有孩子会返回-1
,这会打破循环。
或者ikegami指出这可以简化为:
1 while wait > 0;
(同样的事情,更简洁)