【问题标题】:Perl: store many files content with Parallel::ForkManagerPerl:使用 Parallel::ForkManager 存储许多文件内容
【发布时间】:2018-03-17 01:23:40
【问题描述】:

我有三个文件(两个制表符分隔的字段,文件之间没有冗余)。我想并行读取它们并将它们的内容存储在一个哈希中。

这是我尝试过的:

use warnings;
use strict;
use Parallel::ForkManager;
use Data::Dumper;

my @files = ('aa', 'ab', 'ac');

my %content;
my $max_processors = 3;
my $pm = Parallel::ForkManager->new($max_processors);

foreach my $file (@files) {
    $pm->start and next;

    open FH, $file or die $!;
    while(<FH>){
        chomp;
        my($field1, $field2) = split/\t/,$_;
        $content{$field1} = $field2;
    }
    close FH;

    $pm->finish;
}
$pm->wait_all_children;

print Dumper \%content;

这个脚本的输出是

$VAR1 = {};

我可以看到这三个文件是并行处理的,但是...如何存储三个文件的内容以进行分叉后处理?

【问题讨论】:

  • 为什么要并行读取这些文件?有没有写过解决方案,发现太慢了,然后分析了一下,发现读取文件是个瓶颈?除非您的文件很大并且位于单独的驱动器上,否则您不太可能获得有用的速度提升,并且您的代码实际上更难以阅读和理解。

标签: perl file-io parallel-processing fork


【解决方案1】:

您可以使用run_on_finish() 回调来完成此操作,并将数据存储为参考文件名之类的内容作为键(有关示例,请参阅文档的Data structure retrieval 部分)。

所以,如果你让你的文件读取代码成为一个子程序,让它返回数据作为参考,然后使用回调,你可能会得到这样的结果:

#!/usr/bin/perl
use strict;
use warnings;
use autodie;

use Parallel::ForkManager;
use Data::Dump;

sub proc_file {
    # Read the file and split into a hash; assuming the data struct, based on
    # OP's example.
    my $file = shift;
    open(my $fh, "<", $$file);
    my %content = map{ chomp; split(/\t/) }<$fh>;
    return \%content;
}

my %content;
my @files = ('aa','ab','ac');

my $pm = new Parallel::ForkManager(3);
$pm->run_on_finish(
    sub {
        my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
        my $input_file = $data_structure_reference->{input};
        $content{$input_file} = $data_structure_reference->{result};
    }
);

# For each file, fork a child, and on finish create an object ref to the file
# and the results of processing, that can be stored in the $data_structure_reference.
for my $input_file (@files) {
    $pm->start and next;
    my $return_data = proc_file(\$input_file);

    $pm->finish(0,
        {
          result  => $return_data,
          input   => $input_file,
        }
     );
}
$pm->wait_all_children;

dd \%content;

这将产生一个以文件名为键、内容为子哈希的哈希值,您可以轻松地将其折叠或合并或任何您喜欢的内容:

$ ./parallel.pl a*
{
  aa => { apple => "pear" },
  ab => { Joe => "Wilson" },
  ac => { "New York" => "Mets" },
}

请注意,与任何分叉过程一样,相关的间接费用也相当多,而且这最终可能不会加快您的处理速度,而不仅仅是按顺序循环文件。

【讨论】:

    【解决方案2】:

    当您 fork 时,子进程拥有自己的独立内存,因此父进程无法访问您读入的数据。您可能必须找到一种方法让子进程将数据传回通过管道,但此时您最好不要分叉,直接读取数据。

    您可能想要研究的是使用线程,因为它们共享相同的内存。

    【讨论】:

      猜你喜欢
      • 2018-12-09
      • 2011-01-26
      • 2013-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      相关资源
      最近更新 更多