Вилка в Perl не работает во время чтения цикла из файла - PullRequest
2 голосов
/ 09 апреля 2010

Я выполняю цикл while, читая каждую строку в файле, а затем выполняю процессы fork с данными строки для дочернего элемента. После 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 смешивается, и файл начинает читать в (очевидно) случайных местах, перепрыгивая назад и вперед. Конечным результатом является то, что большинство строк в файле читаются два или три раза. Есть идеи?

Заранее большое спасибо,

С. * * +1010

Ответы [ 2 ]

4 голосов
/ 09 апреля 2010

Вы выходите из дома unless ($pid)?

Если нет, то ваш ребенок после выполнения команды добавит к массиву $pid с нулем и, как правило, продолжит выполнение того, что должно быть кодом родительского процесса.

1 голос
/ 09 апреля 2010

Я обеспокоен тем, что ваш алгоритм не очень эффективен:

Пусть базовый процесс форк обрабатывает от 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;
} 
...