2010-03-16 20 views
8

Her işlemcinin biri olmak üzere 2 iş parçacığı başlatan bir Perl betiğim var. Bir iş parçacığının bitmesini beklemek gerekiyor, eğer bir iş parçacığı biterse yeni bir yumurtlanırsa. Görünüşe göre, birleştirme yöntemi programın geri kalanını engeller, bu nedenle ikinci iş parçacığı, ilk iş parçacığının yaptığı her şey bitene kadar sona ermez.Perl'de, iş parçacığının paralel olarak bitmesini nasıl bekleyebilirim?

is_joinable yöntemini denedim, ancak bu da öyle görünmüyor. İşte

olan kodumu bazıları:

use threads; 
use threads::shared; 

@file_list = @ARGV;  #Our file list 
$nofiles = $#file_list + 1; #Real number of files 
$currfile = 1;  #Current number of file to process 

my %MSG : shared;    #shared hash 

$thr0 = threads->new(\&process, shift(@file_list)); 
$currfile++; 
$thr1 = threads->new(\&process, shift(@file_list)); 
$currfile++; 

while(1){ 
if ($thr0->is_joinable()) { 
    $thr0->join; 
     #check if there are files left to process 
    if($currfile <= $nofiles){ 
    $thr0 = threads->new(\&process, shift(@file_list)); 
    $currfile++; 
    } 
} 

if ($thr1->is_joinable()) { 
    $thr1->join; 
     #check if there are files left to process 
    if($currfile <= $nofiles){ 
    $thr1 = threads->new(\&process, shift(@file_list)); 
    $currfile++; 
    } 
} 
} 

sub process{ 
     print "Opening $currfile of $nofiles\n"; 
     #do some stuff 
     if(some condition){ 
       lock(%MSG); 
       #write stuff to hash 
     } 
     print "Closing $currfile of $nofiles\n"; 
} 

bu çıktısı:

Opening 1 of 4 
Opening 2 of 4 
Closing 1 of 4 
Opening 3 of 4 
Closing 3 of 4 
Opening 4 of 4 
Closing 2 of 4 
Closing 4 of 4 

cevap

5

Sana parçacığı içine listeden sonraki dosyayı çeker kod devam etmeliyiz kendilerini.

Bu nedenle, her iş parçacığı yalnızca bir dosyayı işlemez, ancak liste boşalana kadar işlemeye devam eder.

Bu şekilde, her zaman yeni iş parçacığı oluşturmanın ek yükünü de kaydedersiniz.

Ana iş parçacığınız her ikisine de katılacak. Tabii ki, bu listede senkronizasyonu gerektirir (böylece aynı verileri çekmemek için). Alternatif olarak, listeyi ikiye bölebilirsiniz (her bir iş parçacığı için bir tane), ancak bu da şanssız bir dağılımla sonuçlanabilir.

(PS: Hayır Perl Tanrı ise basit bir keşiş)

+0

Bugün sen benim tanrımsın;) güzel bir çözüm .. Bir şey daha: Kilitleri listeye koymak için şimdi şunu yapın: (1 == 1) {lock (@file_list); $ file = shift (@file_list); } Eğer işlevi çalıştırmadan önce sonunda kilidi açılacaksa buna ihtiyacım var. Bu güzel bir noob-hack gibi görünüyor :) ama daha iyi bir yolu? – Pmarcoen

9

Öncelikle, kod kendisinde birkaç yorumlar. Sen sahip emin olmak gerekir:

use strict; 
use warnings; 

her komut başında. İkinci: skalar bağlamında bir dizi dizideki elementlerin sayısı değerlendirirken

@file_list = @ARGV;  #Our file list 
$nofiles = $#file_list + 1; #Real number of files 

gereksizdir. Yani:

$nofiles = @ARGV; 

doğru $[ değerine bakılmaksızın @ARGV size dosya sayısını verecekti. Nihayet

, senaryo konuları başlamadan önce dosyaların listesini paylaşmak suretiyle çok daha basit hale getirilebilir:

use strict; use warnings; 

use threads; 
use threads::shared; 

my @threads = (
    threads->new(\&process, @ARGV[0 .. @ARGV/2]), 
    threads->new(\&process, @ARGV[@ARGV/2 + 1 .. @ARGV - 1]), 
); 

$_->join for @threads; 

sub process { 
    my @files = @_; 
    warn "called with @files\n"; 
    for my $file (@files) { 
     warn "opening '$file'\n"; 
     sleep rand 3; 
     warn "closing '$file'\n"; 
    } 
} 

Çıktı: Alternatif

C:\Temp> thr 1 2 3 4 5 
called with 1 2 3 
opening '1' 
called with 4 5 
opening '4' 
closing '4' 
opening '5' 
closing '1' 
opening '2' 
closing '5' 
closing '2' 
opening '3' 
closing '3'

, sen ipler geçelim edebilir onlar yapılır sonraki görev:

use strict; use warnings; 

use threads; 
use threads::shared; 

my $current :shared; 
$current = 0; 

my @threads = map { threads->new(\&process, $_) } 1 .. 2; 
$_->join for @threads; 

sub process { 
    my ($thr) = @_; 
    warn "thread $thr stared\n"; 

    while (1) { 
     my $file; 
     { 
      lock $current; 
      return unless $current < @ARGV; 
      $file = $ARGV[$current]; 
      ++ $current; 
     } 
     warn "$thr: opening '$file'\n"; 
     sleep rand 5; 
     warn "$thr: closing '$file'\n"; 
    } 
} 

Çıktı:

C:\Temp> thr 1 2 3 4 5 
thread 1 stared 
1: opening '1' 
1: closing '1' 
1: opening '2' 
thread 2 stared 
2: opening '3' 
2: closing '3' 
2: opening '4' 
1: closing '2' 
1: opening '5' 
1: closing '5' 
2: closing '4'
+0

yorumlarınız için teşekkür ederiz, şimdiden yorumlarınızı okumadan önce Thilo'nun çözümünü uyguladıktan sonra cevabını aldım ama önerilerinizi kesinlikle kullanacağım! – Pmarcoen

+1

Çalışma grubunu önceden bölmek, şanssız bir dağıtım olmasına neden olabilir. – Thilo

İlgili konular