仅在完成子进程

时间:2015-06-02 08:18:07

标签: perl

我想做一些并行子进程,但是,所有子进程都已完成,然后我只想启动/继续我的父进程。下面是我的示例代码

    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

1 个答案:

答案 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;

(同样的事情,更简洁)