在Perl的叉子不工作在从文件读取的while循环里面

时间:2010-04-09 14:40:23

标签: perl file-io fork

我正在运行一个while循环来读取文件中的每一行,然后使用该行的数据将进程分叉到子进程。在N行之后,我想等待子进程结束并继续接下来的N行等等。

它看起来像这样:

    while ($w=<INP>) {

        # ignore file header
        if ($w=~m/^\D/) { next;}

        # get data from line
        chomp $w;
        @ws = split(/\s/,$w);

        $m = int($ws[0]);
        $d = int($ws[1]);
        $h = int($ws[2]);

        # only for some days in the year
        if (($m==3)and($d==15) or ($m==4)and($d==21) or ($m==7)and($d==18)) {

                die "could not fork" unless defined (my $pid = fork);

                unless ($pid) {

                        some instructions here using $m, $d, $h ...

                }
                push @qpid,$pid;

                # when all processors are busy, wait for child processes
                if ($#qpid==($procs-1)) {
                        for my $pid (@qpid) {
                                waitpid $pid, 0;
                        }
                        reset 'q';
                }
        }
}

close INP;

这不起作用。在第一轮进程之后,我得到一些PID等于0,@ qpid数组被混淆,文件开始在(显然)随机位置读取,来回跳跃。最终结果是文件中的大多数行读取了两到三次。有任何想法吗?

提前多多感谢,

S上。

2 个答案:

答案 0 :(得分:4)

您是否正在unless ($pid)内退出?

如果没有,那么你的孩子在运行命令后,会向数组添加零$pid,并且通常继续运行应该是父进程代码

答案 1 :(得分:1)

我担心你的算法效率不高:

让基础进程fork将进程1转换为N.

如果进程2到N在进程1之前完成,那么在进程1完成之前不会启动任何新进程。

使用Parallel::ForkManager轻松获取正确的工作代码,而不是试图获得正确的实施细节。

use strict;
use warnings;
use Parallel::ForkManager;

my $pm = Parallel::ForkManager->new($MAX_PROCESSES);

while( my $w=<INP> ) {

    next if $w=~m/^\D/;        # ignore file header

    chomp $w;

    next unless match_dates( $w,
        { m => 3, d => 15 }, 
        { m => 7, d => 18 },
        { y => 2008       },  # Added this to show match_dates() capability.
    );

    my $pid = $pm->start and next; 

        .. Do stuff in child here ..

    $pm->finish;  # Terminate child
}

close INP;

# Returns true if ANY of the supplied date templates matches for ALL keys defined in that template.
sub match_dates {
    my $string = shift;

    my %target;
    @target{qw( m d y )} = split(/\s/,$string);

    DATE:
    for my $date ( @_ ) {

        my @k = keys %$match;
        my $count = 0;

        for( @k ) {
            next DATE unless $date{$_} == $target{$_};
            $count++;
        }

        return 1 if $count == @k;  # All keys match

    }

    return;
}