2012-04-02 8 views
29

Se si desidera imparare come utilizzare thread Perl, c'è buona documentazione in perlthrtut (threads tutorial) e the threads pragma manpage. È sicuramente abbastanza buono scrivere degli script semplici.Utilizzare casi per ithreads (thread di interprete) in Perl e motivazione per l'utilizzo o non utilizzo di essi?

Tuttavia, ho trovato poche indicazioni sul web su perché e cosa utilizzare per le discussioni sensibilmente l'interprete di Perl per. In realtà, non si parla molto di loro, e se la gente parla di loro è abbastanza spesso scoraggiare la gente dal usarli.

Questi fili, disponibile quando perl -V:useithreads è useithreads='define'; e scatenata da use threads, sono chiamati anche ithreads, e forse più appropriatamente in modo tale che sono molto diversi da discussioni come quelle offerte dai sistemi operativi Linux o Windows o Java VM in che nulla è condiviso per impostazione predefinita e vengono copiati molti dati, non solo lo stack di thread, aumentando così in modo significativo la dimensione del processo. (Per vedere l'effetto, caricare alcuni moduli in uno script di test, quindi creare thread in un ciclo pausa per pressioni di tasti ogni volta, e guardare aumento memoria nel responsabile di operazione o top.)

[...] ogni volta che si avvia un thread tutte le strutture di dati vengono copiate in la nuova discussione. E quando dico tutto, intendo tutto. Questo ad es. include il pacchetto , variabili globali, lessicali nell'ambito. Qualunque cosa!

- Things you need to know before programming Perl ithreads (Perlmonks 2003)

Quando la ricerca oggetto di ithreads Perl, vedrete persone che scoraggiare dal loro utilizzo ("extremely bad idea", "fundamentally flawed", o "never use ithreads for anything").

The Perl thread tutorial highlights that "Perl Threads Are Different", ma non si preoccupa molto di spiegare come sono diversi e cosa significa per l'utente.

Una spiegazione utile ma molto breve di ciò che realmente sono gli ithread è from the Coro manpage under the heading WINDOWS PROCESS EMULATION. L'autore di quel modulo (Coro - gli unici thread reali in perl) scoraggia anche l'uso dei thread dell'interprete Perl.

Da qualche parte ho letto che compilando perl con i thread abilitati si otterrà un interprete molto più lento.

C'è una pagina Perlmonks del 2003 (Things you need to know before programming Perl ithreads), in cui l'autore chiede: "Ora ti potresti chiedere perché i ithreads Perl non hanno usato fork()?" Non avrebbe avuto molto più senso? " Questo sembra essere stato scritto dall'autore del pragma forks. Non sono sicuro che le informazioni fornite su quella pagina siano ancora valide nel 2012 per i nuovi Perls.

Ecco alcune linee guida per l'utilizzo di thread in Perl che ho distillato dalle mie letture (forse erroneamente): così

Finora la mia ricerca. Ora, grazie per la luce in più, puoi chiarire questo problema dei thread in Perl. Quali sono alcuni casi d'uso ragionevoli per gli ithreads in Perl? Qual è la motivazione per l'utilizzo o meno del loro utilizzo?

risposta

21

La risposta breve è che sono piuttosto pesanti (non è possibile lanciarne 100+ a basso costo) e mostrano comportamenti imprevisti (in qualche modo mitigati dai recenti moduli CPAN).

È possibile tranquillamente utilizzare ithreads Perl trattandoli come attori indipendenti.

  1. Creare una discussione :: Coda :: Qualsiasi per "lavoro".
  2. Avvia più ithread e "risultato" Code passandole ("lavoro" + proprio "risultato") Code in chiusura.
  3. Caricare (richiedere) tutto il codice rimanente richiesto dall'applicazione (non prima delle discussioni!)
  4. Aggiungere lavoro per i thread nella coda come richiesto.

In ithread "lavoratore":

  1. Portare in qualsiasi codice comune (per qualsiasi tipo di lavoro)
  2. Blocco-dequeue un lavoro dalla coda
  3. della domanda caricare qualsiasi altre dipendenze richieste per questo pezzo di lavoro.
  4. Fai il lavoro.
  5. Passare il risultato al thread principale tramite la coda "result".
  6. Torna 2.

Se alcuni fili "operaie" iniziano a diventare un po 'robusto, ed è necessario limitare il "lavoratore" thread per qualche numero poi lanciare nuovi al loro posto, quindi creare un " launcher "thread first, il cui compito è quello di avviare i thread" worker "e collegarli al thread principale.

Quali sono i problemi principali con i ithreads Perl?

Sono un po 'scomodi per i dati "condivisi" in quanto è necessario fare la condivisione (non è un grosso problema).

è necessario guardare fuori per il comportamento di oggetti con DISTRUGGERE metodi come vanno fuori portata in qualche filo

The Big One (se sono ancora necessari in un altro!): Dati/variabili che non sono condivisi in modo esplicito sono CLONED in nuovi thread. Questo è un successo nelle prestazioni e probabilmente non è affatto quello che volevi. Il problema è di lanciare i ithread da una condizione "pristine" (non molti moduli caricati).

IIRC, ci sono moduli nel namespace Threads :: che aiutano a rendere esplicite le dipendenze e/o ripulire i dati clonati per i nuovi thread.

Inoltre, IIRC, c'è un modello leggermente diverso usando gli ithreads chiamati thread "Apartment", implementati da Thread :: Appartment che ha un diverso schema di utilizzo e un altro insieme di trade-off.

Il risultato:

Non usarli se non si sa cosa si sta facendo :-)

Forcella può essere più efficiente su Unix, ma la storia IPC è molto più semplice per ithreads. (Questo potrebbe essere stato mitigato dai moduli CPAN dall'ultima volta che ho guardato :-)

Sono ancora meglio dei thread di Python.

Ci potrebbe, un giorno, essere qualcosa di molto meglio in Perl 6.

+0

Grazie! Questa è l'istruzione d'uso più dettagliata per i thread di Perl che ho visto fino ad oggi. - Nella mia domanda ho affermato che il * come * dell'uso di ithreads è coperto mentre il * why * e * what for * mancano. Pensando a questo, * come *, * perché * e * che cosa * sono strettamente correlati, e in realtà * come * non è stato sufficientemente accurato (per gli utenti di Perl comuni come me) per rispondere al * perché * e * cosa per *. - Questa risposta è un passo avanti. Grazie ancora. – Lumi

+0

"Sono ancora migliori dei thread di Python." - puoi spiegare questo? Per favore, è molto interessante. – nordicdyno

+3

Principalmente si tratta del GIL Python nella maggior parte delle implementazioni (prevalentemente cpython ma altre meno estensioni). Fondamentalmente, significa che i thread del sistema operativo su Python non possono effettivamente eseguire contemporaneamente il lavoro della CPU, il che ne sconfigge completamente il punto. Puoi usarli (thread Python) per rendere l'I/O un po 'più concorrente, ma è più semplice utilizzare le API orientate agli eventi per farlo. –

8

ho usato "fili" del Perl in diverse occasioni. Sono più utili per avviare un processo e continuare con qualcos'altro. Non ho molta esperienza nella teoria di come funzionano sotto il cofano, ma ho molta esperienza pratica di programmazione con loro.

Ad esempio, ho un thread del server che ascolta le connessioni di rete in entrata e invia una risposta di stato quando qualcuno lo richiede. Creo quel thread, poi proseguo e creo un altro thread che controlla il sistema, controllando cinque elementi, dormendo alcuni secondi e riavvolgendo di nuovo. Potrebbero essere necessari 3-4 secondi per raccogliere i dati del monitor, quindi vengono inseriti in una variabile condivisa e il thread del server può leggerli quando necessario e restituire immediatamente l'ultimo risultato noto a chi lo richiede. Il thread del monitor, quando rileva che un elemento è in uno stato negativo, avvia un thread separato per riparare quell'elemento. Quindi procede, controllando gli altri elementi mentre quello cattivo viene riparato e dando il via ad altri thread per altri elementi non validi o unendosi ai thread di riparazione terminati. Il programma principale è sempre in loop ogni pochi secondi, assicurandosi che i thread del monitor e del server non siano unibili/ancora in esecuzione. Tutto questo potrebbe essere scritto come una serie di programmi separati che utilizzano qualche altra forma di IPC, ma i thread di Perl lo rendono semplice.

Un altro luogo in cui li ho usati si trova in un generatore di frattali. Vorrei dividere parti dell'immagine usando un algoritmo e poi avviare tanti thread quante sono le CPU per fare il lavoro. Ognuno inseriva i loro risultati in un singolo oggetto GD, che non causava problemi perché ognuno di loro lavorava su porzioni diverse dell'array, e poi, una volta finito, scrivevo l'immagine GD. È stata la mia introduzione all'uso dei thread perl, ed è stata una buona introduzione, ma poi l'ho riscritta in C ed era più veloce di due ordini di grandezza :-). Poi ho riscritto la mia versione con perl per usare Inline :: C, ed era solo il 20% più lento della pura versione C. Tuttavia, nella maggior parte dei casi in cui vorresti utilizzare i thread a causa dell'intensità della CPU, probabilmente vorrai semplicemente scegliere un'altra lingua.

Come accennato da altri, forchetta e fili si sovrappongono davvero per molti scopi. Coro, tuttavia, non consente l'utilizzo multi-CPU o l'elaborazione parallela come fork e thread, vedrai il tuo processo solo al 100%. Sto semplificando eccessivamente questo, ma penso che il modo più semplice per descrivere Coro sia che è uno schedulatore per le tue subroutine. Se hai una subroutine che blocca puoi passare ad un'altra e fare qualcos'altro mentre aspetti, ad esempio hai un'app che calcola i risultati e li scrive in un file. Un blocco potrebbe calcolare i risultati e inserirli in un canale. Quando finisce il lavoro, un altro blocco inizia a scriverli su disco. Mentre quel blocco è in attesa sul disco, l'altro blocco può ricominciare a calcolare i risultati se ottiene più lavoro. Devo ammettere che non ho fatto molto con Coro; sembra un buon modo per accelerare alcune cose, ma sono un po 'scoraggiato dal non poter fare due cose contemporaneamente.

La mia preferenza personale se voglio fare il multiprocessing è usare la forcella se sto facendo molte cose piccole o corte, discussioni per una manciata di cose grandi o di lunga durata.

Problemi correlati