2017-12-01 17 views
1

다음 코드를 사용하여 자체 작성 모듈에서 스레드로 서브 루틴을 전달하려고합니다.Perl hand 모듈에서 스레드

이것은 처음 사용하는 스레드이므로 익숙하지 않습니다.

홈페이지 스크립트 (shortend)

#!/usr/bin/perl -w 
use strict; 
use threads; 

use lib 'PATH TO LIB'; 
use goldstandard; 

my $delete_raw_files = 0; 
my $outfolder = /PATH/; 
my %folder = goldstandard -> create_folder($outfolder,$delete_raw_files); 

&tagging if $tagging == 1; 

sub tagging{ 
    my %hash = goldstandard -> tagging_hash(\%folder); 
    my @threads; 
    foreach(keys %hash){ 
     if($_ =~ m/mate/){ 
      my $arguments = "goldstandard -> mate_tagging($hash{$_}{raw},$hash{$_}{temp},$hash{$_}{tagged},$mate_anna,$mate_model)"; 
      push(@threads,$arguments); 
     } 
     if($_ =~ m/morpheus/){ 
      my $arguments = "goldstandard -> morpheus_tagging($hash{$_}{source},$hash{$_}{tagged},$morpheus_stemlib,$morpheus_cruncher)"; 
      push(@threads,$arguments) 
     } 
    } 
    foreach(@threads){ 
     my $thread = threads->create($_); 
     $thread ->join(); 
    } 
} 

모듈

package goldstandard; 
use strict; 
use warnings; 
sub mate_tagging{ 
    my $Referenz = shift; 
    my $input = shift; 
    my $output_temp_dir = shift; 
    my $output_mate_human = shift; 
    my $anna = shift; 
    my $model = shift; 
    opendir(DIR,"$input");             
    my @dir = readdir(DIR); 
    my $anzahl = @dir; 
    foreach(@dir){ 
     unless($_ =~ m/^\./){ 
      my $name = $_; 
      my $path = $input . $_; 
      my $out_temp = $output_temp_dir . $name; 
      my $out_mate_human_final = $output_mate_human . $name; 
      qx(java -Xmx10G -classpath $anna is2.tag.Tagger -model $model -test $path -out $out_temp); 
      open(OUT, "> $out_mate_human_final"); 
      open(TEMP, "< $out_temp"); 
      my $output_text; 
      while(<TEMP>){ 
       unless($_ =~ m/^\s+$/){ 
        if ($_ =~ m/^\d+\t(.*?)\t_\t_\t_\t(.*?)\t_\t/) { 
         my $tags = $2; 
         my $words = $1; 
         print OUT "$words\t$tags\n"; 
        } 
       } 
      } 
     } 
    } 
} 

sub morpheus_tagging{ 
    my $Referenz = shift; 
    my $input = shift; 
    my $output = shift; 
    my $stemlib = shift; 
    my $cruncher = shift; 
    opendir(DIR,"$input");             
    my @dir = readdir(DIR); 
    foreach(@dir){ 
     unless($_ =~ m/^\./){ 
      my $name = $_; 
      my $path = $input . $_; 
      my $out = $output . $name; 
      qx(env MORPHLIB='$stemlib' '$cruncher' < '$path' > '$out'); 
     } 
    } 
} 

1; 

이 코드를 실행하는

Thread 1 terminated abnormally: Undefined subroutine &main::goldstandard -> morpheus_tagging(...) called at ... line 43. 

은 내가이 자국 또는 방법 I를 호출하고 eather 방법을 생각 나에게 도착 논쟁을 제공하는 것이 잘못되었습니다. 나는 그걸로 나를 도울 수 있기를 바래? 나 또한 안전하고 안전하지 않은 모듈에 대해 뭔가를 발견했다. 나는 이것이 정말로 문제인지 확실하지 않다.

내가 트레드를 호출하는 방식 또는 인수를 제공하는 방식이 잘못되었다고 생각합니다. 나는 그걸로 나를 도울 수 있기를 바래? 나는 안전하고 안전하지 않은 모듈에 대해서도 발견했다. 나는 이것이 정말로 문제가되는지 확실하지 않다. 사전에 감사한다.

+0

[문서는은'threads' 프라 그마 (https://perldoc.perl.org/threads.html) 명확하게 create' '에 첫 번째 매개 변수의 이름이 포함 된 문자열이어야합니다 말한다 스레드에 대한 코드를 제공하는 서브 루틴 또는 해당 서브 루틴에 대한 참조 다음 매개 변수는 호출 매개 변수로 서브 루틴에 직접 전달됩니다. 해당 옵션 중 하나가 아닌 컴파일되지 않은 Perl 코드 문자열을 전달했습니다. 또한,'goldstandard -> morpheus_tagging'은 문자열'goldstandard'를 첫 번째 매개 변수로 전달하는 클래스 메소드 호출입니다. – Borodin

답변

4

하위의 이름이나 하위 참조, 더하기 인수의 이름을 threads->create으로 전달해야한다. 그래서 당신은 threads->create에 인수를 전달했다

my $method_ref = $invoker->can($method_name); 
threads->create($method_ref, $invoker, @args); 

같은 뭔가가 필요하면 폐쇄를 사용하여 방지 할 수 있습니다 문제가 있습니다.

threads->create(sub { $invoker->$method_name(@args) }) 

다음과 같이 위의 더 간단하게 작성할 수 있습니다

async { $invoker->$method_name(@args) } 

이것은 다음과 같은 우리를 가져옵니다

sub tagging { 
    my %hash = goldstandard->tagging_hash(\%folder); 

    my @jobs; 
    for (keys %hash) { 
     if (/mate/) { 
      push @jobs, [ 'goldstandard', 'mate_tagging', 
       $hash{$_}{raw}, 
       $hash{$_}{temp}, 
       $hash{$_}{tagged}, 
       $mate_anna, 
       $mate_model, 
      ]; 
     } 

     if (/morpheus/) { 
      push @jobs, [ 'goldstandard', 'morpheus_tagging', 
       $hash{$_}{source}, 
       $hash{$_}{tagged}, 
       $morpheus_stemlib, 
       $morpheus_cruncher, 
      ]; 
     } 
    } 

    my @threads; 
    for my $job (@jobs) { 
     my ($invoker, $method_name, @args) = @$job; 
     push @threads, async { $invoker->$method_name(@args) }; 
    } 

    $_->join for @threads; 
} 

또는 내가 연기 단지

sub tagging { 
    my %hash = goldstandard->tagging_hash(\%folder); 

    my @threads; 
    for (keys %hash) { 
     if (/mate/) { 
      push @threads, async { 
       goldstandard->mate_tagging(
        $hash{$_}{raw}, 
        $hash{$_}{temp}, 
        $hash{$_}{tagged}, 
        $mate_anna, 
        $mate_model, 
       ); 
      }; 
     } 

     if (/morpheus/) { 
      push @threads, async { 
       goldstandard->morpheus_tagging(
        $hash{$_}{source}, 
        $hash{$_}{tagged}, 
        $morpheus_stemlib, 
        $morpheus_cruncher, 
       ); 
      }; 
     } 
    } 

    $_->join for @threads; 
} 

노트에 대한 전화모든 스레드가 생성 될 때까지 당신의 방법은 한 번에 하나의 스레드 만 실행하도록 만들었습니다.

하지만 우리가 가진 것은별로 좋지 않습니다. 한 번에 얼마나 많은 스레드가 활성 상태인지 제한 할 수있는 방법이 없으며, 재사용하지 않고 많은 스레드를 (비싸게) 생성합니다. 작업자 풀을 사용하여이 두 가지 문제를 모두 해결할 수 있습니다.

use constant NUM_WORKERS => 5; 

use Thread::Queue 3.01 qw(); 

my $q; 

sub tagging { 
    my %hash = goldstandard->tagging_hash(\%folder); 

    my @threads; 
    for (keys %hash) { 
     if (/mate/) { 
      $q->enqueue(sub { 
       goldstandard->mate_tagging(
        $hash{$_}{raw}, 
        $hash{$_}{temp}, 
        $hash{$_}{tagged}, 
        $mate_anna, 
        $mate_model, 
       ); 
      }); 
     } 

     if (/morpheus/) { 
      $q->enqueue(sub { 
       goldstandard->morpheus_tagging(
        $hash{$_}{source}, 
        $hash{$_}{tagged}, 
        $morpheus_stemlib, 
        $morpheus_cruncher, 
       ); 
      }); 
     } 
    } 
} 

{ 
    $q = Thread::Queue->new(); 

    for (1..NUM_WORKERS) { 
     async { 
      while (my $job = $q->dequeue()) { 
       $job->(); 
      } 
     }; 
    } 

    ... call tagging and whatever ... 

    $q->end(); 
    $_->join() for threads->list(); 
} 
+0

놀랍습니다. 고맙습니다! –

+0

내가보기에, 여전히 문제가있는 것 같다. $ q-> enqueue (sub {.... undef 값에 "enqueue"메쏘드를 호출 할 수 없다. 그러나 정의되어있다. 모두 자체적으로 사용하는 경우 작동합니다. –