Как заставить два perl-файла общаться? - PullRequest
0 голосов
/ 17 декабря 2010

Итак, у меня есть что-то вроде этого:

fork.pl

for $str (@files)  
{        
    my($command) = "perl command.pl ".$str;
    exec( $command );
}

command.pl

$file=$ARGV[0].".csv";
#code that counts rows here
print $rowcount;

Итак, в результате я запустил 10 файлов, которые подсчитывают, сколько строк в каждом CSV-файле.

Мне не нужна помощь в редактировании этого кода, он работает (это просто сжатая версия).Мне нужна помощь, чтобы понять, как взять выходные данные ($ rowcount) из десяти файлов и объединить их в один для дальнейшей обработки.

Ответы [ 5 ]

3 голосов
/ 17 декабря 2010

Я держу некоторый служебный код только для этой цели ... это немного подправлено для вашего вопроса и включает в себя метод синхронизированного глобального подсчета.

#!/usr/bin/perl
use threads;
use Thread::Queue;

my @workers;
my $num_threads = 10;
my $queue = new Thread::Queue;
my $total_ines = 0;

for (0..$num_threads-1) {
        $workers[$_] = new threads(\&worker);
}

while ($_ = shift @ARGV) {
        $queue->enqueue($_);
}

sub worker() {
        while ($file = $queue->dequeue) {
            #line counting code here
            global_counter($lines_counted);
        }
}

sub global_counter() :locked {
    #add to the number of lines counted
    $total_lines += shift
}

for (0..$num_threads-1) { $queue->enqueue(undef); }
for (0..$num_threads-1) { $workers[$_]->join; }

print $total_lines;
2 голосов
/ 17 декабря 2010

Этот тип связи решается с помощью каналов (позвольте мне написать простой пример):

# -- fork.pl -------------------------
for (1..3)  {        
   open my $PIPE, "perl command.pl |";
   print "catch: $_\n" while(<$PIPE>);
   close $PIPE;
}
# -- command.pl ----------------------
print rand(1);

Он печатает (случайные числа):

catch: 0.58929443359375
catch: 0.1290283203125
catch: 0.907012939453125
0 голосов
/ 17 декабря 2010

Накапливайте каналы от детей:

#!/usr/bin/perl -w

use strict;

my $files = qw/one.csv two.csv three.csv/;
my $command = "perl command.pl";

my @pipes;
foreach (@files) {
    my $fd;
    open $fd, "-|", "$command $_" and push @pipes, $fd;
};

my $sum = 0;
foreach my $pp (@pipes) {
    $sum += $_ if defined ($_=<$pp>);
};

print $sum;

Затем вы можете просто прочитать их один за другим (как в примере) или use IO::Select, чтобы прочитать данные в том виде, в каком они появляются в каждом канале.

Хеш-таблица в дополнение к массиву также хороша, если вы хотите знать, какие данные поступают из какого источника.

0 голосов
/ 17 декабря 2010

Сжат, но не будет работать. Я предполагаю, что в fork.pl вы форкаете перед выполнением? Обратные метки фиксируют выходные данные вызванного процесса, а именно ваши отпечатки: fork.pl

for $str (@files)  
{        
    my($command) = "perl command.pl ".$str;
    print `$command`;
}

Но вместо того, чтобы разветвлять и запускать процессы, не было бы разумнее превратить второй файл в модуль?

package MyCommand;
use Exporter;

our @EXPORT = qw( command );
sub command {
   my $file = $_[0] . '.csv';

   ...
   return $rowcount;
}

1;

fork.pl:

use MyCommand;

...
my @rowcounts;
for my $str (@files) {        
    push @rowcounts, command($str);
}

Немного саморекламы, но я только что опубликовал это в другой ветке, которая кажется достаточно актуальной: Как запустить параллельно две дочерние команды из родительской?

0 голосов
/ 17 декабря 2010

Вам нужно посмотреть либо на потоки, либо на межпроцессное взаимодействие, например. сокеты или разделяемая память при использовании fork.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...