2017-10-05 7 views
1

세 개의 파일 (두 개의 탭으로 구분 된 필드가 있으며 파일 사이에 중복이 없습니다)이 있습니다. 나는 그들을 병렬로 읽고 그들의 내용을 하나의 해시로 저장하고 싶다. Perl : Parallel :: ForkManager로 많은 파일 내용을 저장하십시오.

내가 뭘하려 :

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 = {}이다;

3 개의 파일이 병렬로 처리되는 것을 볼 수는 있지만 어떻게 포크 후 처리를 위해 3 개의 내용을 저장할 수 있습니까?

+0

왜 이러한 파일을 병렬로 읽으려고하십니까? 솔루션을 작성했는데 속도가 너무 느리다면 프로파일 링 한 결과 파일을 읽는 것이 병목 현상이라는 것을 알았습니까? 파일이 크고 별도의 드라이브에 있지 않으면 속도가 향상되지 않을 수 있으며 코드를 이해하기가 훨씬 어려워집니다. – Borodin

답변

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" }, 
} 

참고, 그 어떤 포크 (fork) 절차처럼 꽤있다 약간의 오버 헤드 비용이 관련되어 있습니다. 그러면이 속도가 끝나지 않을 수도 있습니다. 파일을 순차적으로 순회하는 것 이상으로 처리해야합니다.

1

포크 할 때 하위 프로세스에는 자체 메모리가 있으므로 부모는 읽은 데이터에 액세스 할 수 없습니다. 자식이 데이터를 다시 통신 할 수있는 방법을 찾아야합니다. 어쩌면 파이프를 통해,하지만 그 시점에서 당신은 포크로 신경 쓰지 않고 직접 데이터를 읽을 수 있습니다.

아마 당신이 조사하고 싶은 것은 스레드가 동일한 메모리를 공유하므로 쓰레드를 사용하는 것입니다.