0

プログラムでサブルーチンのスレッドを作成しようとしています(組換えと呼ばれます)。以下のコードを使用してスレッドを作成しました。これはhttp://chicken.genouest.org/perl/multi-threading-with-perl/から採用したものです。これらのスレッドはループで作成されるため、このコードを使用しました。ループごとに異なる変数$ParentTallyに依存するスレッドの数(および$ ParentTallyは最大1000であり、一度に1000スレッドを実行したくありませんでした)

my $nb_process = 20;
my $nb_compute = $ParentTally;
my $i=0;
my @running = ();
my @Threads;
my %NewPopulation;

while (scalar @Threads < $nb_compute) {
    @running = threads->list(threads::running);
    if (scalar @running < $nb_process) {
        my $Offspring= threads->new (sub {Recombination(\%Parent1Chromosome, \%Parent2Chromosome)});
        push (@Threads, $Offspring);
        my $tid = $Offspring->tid;
    }

    @running = threads->list(threads::running);
    foreach my $thr (@Threads) {
        if ($thr->is_running()) {
           my $tid = $thr->tid;
        }
       elsif ($thr->is_joinable()) {
          my $tid = $thr->tid;
          my $Offspring1=$thr->join();
          $NewPopulation{$Offspring1}{'Tally'}+=1;
       }
    }
    @running = threads->list(threads::running);
    $i++;
}

while (scalar @running != 0) {
     foreach my $thr (@Threads) {
      if ($thr->is_joinable()){
         my $Offspring1=$thr->join(); 
         $NewPopulation{$Offspring1}{'Tally'}+=1;
      }
    }
    @running = threads->list(threads::running);
}

(注:$ ParentTallyは、コードの前半にある別のハッシュ、my $ ParentTally = $ hashref-> {'Tally'}から取得されるため、プログラムのこの部分は、毎回$ ParentTallyの異なる値でループします。%Parent1Chromosome& %Parent2Chromosomeは、プログラムの早い段階で作成されます。サブルーチン'Recombination'は非常に長いため、投稿していませんが、整数を返します。)

多くの場合、プログラムを実行すると(常にではありませんが、以前のコードの多くは確率変数に依存しているため、プログラムが同じように実行されることはありません)、プログラムが終了すると、「Perlはアクティブなスレッドで終了します:」「number」が終了し、結合されていません」( 「数」は実行によって異なります)。私はそれを考えました:

 while (scalar @running != 0) {
     foreach my $thr (@Threads) {
      if ($thr->is_joinable()){
         my $Offspring1=$thr->join(); 
         $NewPopulation{$Offspring1}{'Tally'}+=1;
      }
    }

コードの次のセクションに進む前に、すべてのスレッドが終了することを意味しますか?私は何が間違っているのですか?(私はこれまでスレッドを使用したことがありません)。http://www.perlmonks.org/?node_id=735931の使用を検討しましたが、Thread :: Queueの使用方法がよくわからず、チュートリアルを見つけることができませんでした(そして、httpを理解していませんでした)。 ://perldoc.perl.org/Thread/Queue.html)。ありがとう

4

2 に答える 2

4

コードの修正ではありませんが、キューを使用してそれを行う方法の概要を以下に示します(明らかに、目的に合わせていくつかの入力が必要です)。メモリの使用が問題である場合、これを改善する方法はたくさんあります。生成された各スレッドは、スコープ変数内のすべての完全なコピーを取得します。スレッドを使用すると、メモリの問題が発生しやすくなります

#!/usr/bin/perl

use strict ;
use threads ;
use Thread::Queue ;

my $threadCount = 2 ;

my $DataQueue = Thread::Queue->new() ;
my $ReportQueue = Thread::Queue->new() ;

my $threads = [] ;

# create pool of worker threads
for ( my $i = 0 ; $i<$threadCount ; $i ++ ){
    push( @$threads, threads->create( \&doStuff, $DataQueue, $ReportQueue ) ) ;
}

# array of data on which the threads have to work
my @array ;
# put work onto queue for threads to process
foreach my $workItem ( @array ){
   $DataQueue->enqueue( $workItem );
}

# enqueue undef for each worker to tell it no more work
# then wait for them all to join
$DataQueue->enqueue( (undef) x $threadCount ) ;
$_->join for @$threads ;

my %NewPopulation ;
# read the output of the threads from ReportQueue
while ( my $reportItem = $ReportQueue->dequeue() ){
    $NewPopulation{$reportItem}{'Tally'}++ ;
}

# display tallys
for my $offspring ( keys %NewPopulation ){
    print "Offspring $offspring Tally => " . $NewPopulation{$offspring}{'Tally'} . "\n" ;
}

sub doStuff{
    my ( $DataQueue, $ReportQueue ) = @_ ;

    while ( my $inputHash = $DataQueue->dequeue() ){
        my $result ;
        # do things here - the logic in your Recombination sub

        # return result to report queue
        $ReportQueue->enqueue($result) ;
    }

   # Enqueue undef to report queue so report thread knows we're done
   $ReportQueue->enqueue( undef ) ;

}
于 2012-06-20T15:33:15.240 に答える
2

エラーは最後のwhileループにあると思います:

while (scalar @running != 0) {
     foreach my $thr (@Threads) {
      if ($thr->is_joinable()){
         my $Offspring1=$thr->join(); 
         $NewPopulation{$Offspring1}{'Tally'}+=1;
      }
    }
    @running = threads->list(threads::running);
}

スレッドのドキュメントによると、 への呼び出しは、スレッドの実行が終了し、切り離されておらず、まだ結合されていないis_joinable場合にのみ true を返します。私の推測では、このセクションに到達しても実行中のスレッドが残っているため、それらをスキップします。前のループで行ったように、別の呼び出しを行って、スレッドがまだ実行されているかどうかを確認し、何らかの方法でスレッドを処理することができます。whileis_running

于 2012-06-20T15:10:10.200 に答える