我正在尝试在程序中创建子程序的线程(称为重组)。我使用下面的代码来创建线程,我从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取自代码中较早的另一个散列,我的$ ParentTally = $ hashref-&gt; {'Tally'};因此程序的这一部分循环使用$ ParentTally的不同值每次。 %Parent1Chromosome&amp; %Parent2Chromosome是在程序的早期创建的。 子程序'Recombination'很长,所以我没有发布它,但它返回一个整数。 )
通常在运行程序时(尽管并非总是如此,很多早期的代码依赖于随机变量,因此程序永远不会运行相同的)一旦完成,我得到'Perl退出活动线程:'数字'完成并且unjoined'('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)。感谢
答案 0 :(得分: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 ) ;
}
答案 1 :(得分: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);
}
根据threads document,只有在线程已完成,尚未分离且尚未加入的情况下,对is_joinable
的调用才会返回true。我的猜测是,当你到达这个部分时,你仍然有正在运行的线程,所以你跳过它们。您可以像在前一个while
循环中那样,再次调用is_running
来查看是否仍然运行线程并以某种方式处理线程。