2012-07-21 21 views
5

Ho un programma (Perl) che prende il via una quantità enorme di fili (ognuno incaricato di creare grafica basata sul trattamento dei dati). Ogni thread comincio utilizzando:Come limitare il numero massimo di thread paralleli in perl

my @threads //list to store threads that have been launched 

push @threads,threads->create(\mySubName,params...); 

I fili fuoco spento correttamente, ma dopo un po ', dopo aver aperto alcuni di loro crash dell'interprete Perl (suppongo che è legato alla memoria?). Quindi la mia soluzione è quella di limitare il numero di thread apro alla volta, ho preso 15. E voglio aggiungere un sub prima di ogni linea di creare per controllare se è ok per sparare il filo successivo o eseguire un sonno mentre aspetto per uno per finire. Questo è il modo in cui ho provato a farlo.

sub checkThreads{ 
    my $addThread = 0; 
    until($addThread){ 
     my $totalThreads = 0; 
     foreach my $task (@threads){ 
      if($task->is_running()){$totalThreads++;} 
     } 
     if($totalThreads <= 15){ 
      print "Ok to add new thread, carry on!\n"; 
      $addthread = 1; 
     }else{ 
      print "Waiting for $totalThreads threads to fire next one...\n"; 
      sleep 2; 
     } 
    } 
} 

Così ogni volta che voglio creare un nuovo thread vorrei solo richiamare

&checkThreads; 

E che si sarebbe preso cura di creare un ritardo mentre aspetto che alcuni fili per ripulire. Il problema è che quando chiamo che sub, il momento in cui mi ha colpito la linea dove verifico:

$task->is_running() 

il programma termina e smette di funzionare senza alcun errore o avviso. Voglio solo un sub che conti i thread in esecuzione per limitarli.

Come posso eseguire questo conteggio con successo?

Altre cose che ho provato stanno valutando la seguente riga:

scalar(threads->list()); 

ma che mi dà un valore di strano, come si tratta di un riferimento unblessed Credo che assomiglia:

threads=SCALAR(0x80fea8c) 
+0

btw, che è (in stringa di a) * benedetta * ref – ikegami

+1

molto, molto BTW - fare tenere a mente che le discussioni in perl non sono come le discussioni in altri linguaggi di programmazione - sono molto affamato di risorse, dal momento che ogni thread dispone di una copia di tutte le variabili.Sono ancora utili in alcuni casi, ma in tutti i casi in cui devo fare la paralellizzazione, la forking funziona molto meglio. Non è collegato direttamente alla tua domanda, volevo solo dirti questo. :) –

+0

Quale versione di Perl? Quale versione dei thread? E i tuoi thread sono distaccati (forse il self-detaching in mySubName)? – pilcrow

risposta

5

Thread::Semaphore fornisce un counting semaphore per limitare la concorrenza:

my $sem = Thread::Semaphore->new(15); # max 15 threads 
my @threads = map { 
    # request a thread slot, waiting if none are available: 
    $sem->down; 
    threads->create(\&mySubName, @params) 
} 0..100; 
$_->join for @threads; 

E nella funzione:

sub mySubName { 
    do_stuff(); 
    # release slot: 
    $sem->up; 
} 
+0

Richard Penso che funzioni, l'ho implementato nella sceneggiatura e sembra davvero che stia controllando i miei thread max, c'è un modo in cui posso dare un'occhiata al valore corrente di un semaforo? Perché l'ho eseguito ma dopo averlo eseguito per un po 'il mio script si blocca su un '$ sem-> down;' – gorba

+0

Ho ridotto la quantità di thread a 5 e funziona bene, ancora con 7 sembra che il programma si blocchi qualche punto, non sono sicuro del perché. Grazie per il consiglio! – gorba

+1

È possibile ottenere il valore di valuta del semaforo mediante la dereferenziazione dell'oggetto stesso, che è solo un riferimento benedetto al valore massimo (valore predefinito di 1) meno i suoi conteggi. Quindi, per ottenere il numero corrente di thread in sospeso, valuta '$ max - $$ sem'. –

0
man perlthrtut 

What Threads Are Running? 
    "threads->list()" returns a list of thread objects, one for each thread 
    that's currently running and not detached. Handy for a number of 

in altre parole, scoprire quanti elementi sono nella lista che threads-> lista() ritorna e si dispone il valore del tuo.

Si potrebbe voler esaminare Thread::Pool o altri pacchetti cpan per vedere se qualcun altro ha già fatto il lavoro pesante per voi.

+0

Quando provo ad usare threads-> list(), ottengo il seguente risultato: Impossibile trovare auto/threads/lists.al in @INC (@INC contiene: C: \ Programmi (x86) \ ActiveState Komodo 3.5 \ lib \ support \ dbgp \ perllib C: \ Programmi (x86) \ ActiveState Komodo 3.5 \ lib \ support \ dbgp \ perllib C:/Perl/lib C:/Perl/sito/lib.) in C: \ percorso \ main3.pl line 508 – gorba

+0

Se 'threads-> list()' restituisce una lista, puoi catturare la lunghezza più facilmente che con un ciclo ... come '$ totalThreads = scalare (threads-> list());', non puoi? –

+0

ok era un refuso, avevo thread-> lists() invece di threads-> list(), ma ora eseguo questo my $ totalThreads; foreach my $ thr (threads-> list()) { $ totalThreads ++; } stampa "Thread attivo:". $ totaleTread. "\ N"; E ciò che ottengo è: Uso di valore non inizializzato nella concatenazione per la linea in cui si stampa – gorba

1

cerca i documenti,

my $count = threads->list(); 

dovrebbero lavorare, al contrario di quello che dici. Che cosa la documentazione per la versione di fili si utilizza dire? Bene, è possibile utilizzare il seguente come soluzione alternativa.

my $count =() = threads->list(); 
+0

Ho usato l'approccio del semaforo proposto da Richard, ma ho provato questo e dà il conto dei thread attuali nella lista, grazie! – gorba

Problemi correlati