Domanda

Quali sono i moduli utilizzati per scrivere applicazioni multi-thread in Python?Sono a conoscenza dei meccanismi di concorrenza di base forniti dal linguaggio e anche di Pitone senza stack, ma quali sono i rispettivi punti di forza e di debolezza?

È stato utile?

Soluzione

Al fine di complessità crescente:

Utilizzare il filettatura modulo

Pro:

  • E 'davvero facile per eseguire qualsiasi funzione (qualsiasi callable appunto) nella sua proprio thread.
  • Condivisione di dati è se non facile (serrature non sono mai facili :), a almeno semplice.

Contro:

  • Come menzionato da fili Juergen Python non può effettivamente accedere concorrentemente stato l'interprete ( c'è un grosso lucchetto, il famigerato Global Interpreter Lock .) ciò significa, in pratica, è che le discussioni siano utile per I / O compiti legati (networking, la scrittura su disco, e così via), ma non è affatto utile per fare il calcolo simultaneo.

Utilizzare il multiprocessing modulo

Nel caso semplice utilizzo questo appare esattamente come con threading salvo ogni attività viene eseguita nel proprio processo non proprio thread. (Quasi letteralmente: Se si prende di Eli esempio , e sostituire threading con multiprocessing, Thread, con Process, e Queue (modulo) con multiprocessing.Queue, dovrebbe funzionare bene.)

Pro:

  • concorrenza effettiva per tutte le attività (No Global Interpreter Lock).
  • bilance a più processori, può anche scalare a più macchine .

Contro:

  • I processi sono più lento di discussioni.
  • condivisione dei dati tra processi è più complicato di quanto con fili.
  • La memoria non è implicitamente condiviso. O si devono condividere esplicitamente o si deve salamoia variabili e inviarli avanti e indietro. Questo è più sicuro, ma più difficile. (Se è importante sempre più gli sviluppatori Python sembrano spingere le persone in questa direzione.)

Utilizzare un modello di eventi, come ad esempio ritorto

Pro:

  • È possibile ottenere un controllo estremamente preciso su priorità, su ciò che viene eseguito quando.

Contro:

  • Anche con una buona biblioteca, programmazione asincrona di solito è più difficile di quanto la programmazione filettato, difficile sia in termini di comprensione di ciò che suppone accada e in termini di debug che cosa realmente sta accadendo.

tutti i casi Sto assumendo che già capito molti dei problemi connessi con il multitasking, in particolare la questione spinosa di come condividere i dati tra le attività. Se per qualche motivo non si sa quando e come utilizzare i blocchi e le condizioni si deve cominciare con quelli. codice multitasking è pieno di sottigliezze e trucchi, ed è davvero meglio avere una buona comprensione dei concetti prima di iniziare.

Altri suggerimenti

Hai già ricevuto una discreta varietà di risposte, dai "thread falsi" fino ai framework esterni, ma non ho visto nessuno menzionare Queue.Queue -- la "salsa segreta" del threading CPython.

Espandere:purché non sia necessario sovrapporsi all'elaborazione pesante della CPU Python pura (nel qual caso è necessario multiprocessing - ma arriva con il suo Queue anche l'implementazione, così puoi, con alcune precauzioni necessarie, applicare i consigli generali che sto dando;-), il built-in di Python threading andrà bene...ma lo farà molto meglio se lo usi consigliatamente, ad esempio, come segue.

"Dimentica" la memoria condivisa, presumibilmente il vantaggio principale del threading rispetto al multiprocessing: non funziona bene, non si adatta bene, non lo ha mai fatto, non lo farà mai.Utilizzare la memoria condivisa solo per strutture dati configurate una volta Prima generi sotto-thread e non sei mai cambiato in seguito - per tutto il resto, crea un separare thread responsabile di quella risorsa e comunicare con quel thread tramite Queue.

Dedica un thread specializzato a ogni risorsa che normalmente penseresti di proteggere tramite lucchetti:una struttura di dati mutabile o un suo gruppo coeso, una connessione a un processo esterno (un DB, un server XMLRPC, ecc.), un file esterno, ecc., ecc.Ottieni un piccolo pool di thread per attività generiche che non hanno o non necessitano di una risorsa dedicata di quel tipo: non genera thread come e quando necessario, altrimenti il ​​sovraccarico del cambio di thread ti sopraffarà.

La comunicazione tra due thread avviene sempre tramite Queue.Queue - una forma di passaggio di messaggi, l'unica base sana per il multiprocessing (oltre alla memoria transazionale, che è promettente ma per la quale non conosco implementazioni degne di produzione tranne In Haskell).

Ogni thread dedicato che gestisce una singola risorsa (o un piccolo insieme coeso di risorse) ascolta le richieste su un'istanza Queue.Queue specifica.I thread in un pool attendono su una singola Queue.Queue condivisa (Queue è solidamente thread-safe e non deluderti in questo).

I thread che devono solo mettere in coda una richiesta su una coda (condivisa o dedicata) lo fanno senza attendere i risultati e vanno avanti.I thread che eventualmente necessitano di un risultato o di una conferma per una richiesta mettono in coda una coppia (request, gettingqueue) con un'istanza di Queue.Queue appena effettuata, ed eventualmente, quando la risposta o la conferma è indispensabile per procedere, ottengono (in attesa ) dalla coda di ricezione.Assicurati di essere pronto a ricevere risposte di errore così come risposte o conferme reali (Twisted's deferreds sono bravissimi nell'organizzare questo tipo di risposta strutturata, A proposito!).

Puoi anche utilizzare Queue per "parcheggiare" istanze di risorse che possono essere utilizzate da qualsiasi thread ma non essere mai condivise tra più thread contemporaneamente (connessioni DB con alcuni componenti DBAPI, cursori con altri, ecc.) - questo ti consente di rilassarti il requisito del thread dedicato a favore di un maggiore pooling (un thread del pool che riceve dalla coda condivisa una richiesta che necessita di una risorsa accodabile otterrà quella risorsa dalla coda appropriata, in attesa se necessario, ecc. Ecc.).

Twisted è in realtà un buon modo per organizzare questo minuetto (o quadriglia a seconda dei casi), non solo grazie ai differiti ma grazie alla sua architettura di base solida, solida e altamente scalabile:puoi organizzare le cose in modo da utilizzare thread o sottoprocessi solo quando veramente giustificato, mentre fai la maggior parte delle cose normalmente considerate degne di thread in un singolo thread guidato dagli eventi.

Ma mi rendo conto che Twisted non è per tutti: l'approccio "dedicare o raggruppare risorse, utilizzare Queue up the wazoo, non fare mai nulla che richieda un Lock o, Guido non voglia, qualsiasi procedura di sincronizzazione ancora più avanzata, come un semaforo o una condizione" può può ancora essere utilizzato anche se non riesci a capire le metodologie asincrone basate sugli eventi e fornirà comunque più affidabilità e prestazioni rispetto a qualsiasi altro approccio di threading ampiamente applicabile in cui mi sia mai imbattuto.

Dipende da quello che stai cercando di fare, ma io ho un debole per solo utilizzando il modulo threading nella libreria standard perché rende veramente facile da prendere qualsiasi funzione e basta eseguirlo in un thread separato.

from threading import Thread

def f():
    ...

def g(arg1, arg2, arg3=None):
    ....

Thread(target=f).start()
Thread(target=g, args=[5, 6], kwargs={"arg3": 12}).start()

E così via. Mi capita spesso di una messa a punto produttore / consumatore utilizzando una coda sincronizzato fornita dal modulo Queue

from Queue import Queue
from threading import Thread

q = Queue()
def consumer():
    while True:
        print sum(q.get())

def producer(data_source):
    for line in data_source:
        q.put( map(int, line.split()) )

Thread(target=producer, args=[SOME_INPUT_FILE_OR_SOMETHING]).start()
for i in range(10):
    Thread(target=consumer).start()

Kamaelia è un framework Python per la creazione di applicazioni con un sacco di processi comunicanti.

  

     

(fonte: kamaelia.org ) Kamaelia - Concurrency reso utile, divertente

     

In Kamaelia a costruire sistemi di semplici componenti che parlano tra loro . Questo accelera lo sviluppo, in maniera massiccia aiuta manutenzione e significa anche che si costruire naturalmente software concorrente . E 'destinato ad essere accessibile da qualsiasi di sviluppo, compresi i novizi. Inoltre lo rende divertente :)

     

Che tipo di sistemi? server di rete, client, applicazioni desktop, giochi basati pygame, sistemi di transcodifica e tubazioni, sistemi di TV digitale, ancore di spam, strumenti didattici, e una discreta quantità di più :)

Ecco un video da PyCon 2009. Si inizia mettendo a confronto Kamaelia a ritorto e Python Parallel e poi dà un mani sulla dimostrazione di Kamaelia.

Facile concorrenza con Kamaelia - Parte 1 (59:08)
Facile concorrenza con Kamaelia - Parte 2 (18:15)

Per quanto riguarda Kamaelia, la risposta di cui sopra non realmente copre il beneficio qui. L'approccio di Kamaelia fornisce un'interfaccia unificata, che è pragmatico non perfetto, per trattare con filati, generatori e processi in un unico sistema per la concorrenza.

Fondamentalmente fornisce una metafora di una cosa in esecuzione che ha caselle di posta e caselle di uscita. Si invia messaggi a caselle di uscita, e quando cablata insieme, i messaggi flusso da caselle di uscita a caselle di posta. Questa metafora / API rimane lo stesso se si sta utilizzando generatori, thread o processi, o parlare ad altri sistemi.

La parte "non perfetto" è dovuta a zucchero sintattico non essere aggiunto ancora per caselle di posta e caselle di uscita (anche se questo è in discussione) -. C'è un focus sulla sicurezza / usabilità del sistema

Prendendo l'esempio produttore consumatore utilizzando threading nuda sopra, questo diventa questo Kamaelia:

Pipeline(Producer(), Consumer() )

In questo esempio non importa se questi sono filettate componenti o altrimenti, l'unica differenza tra di loro dal punto di vista di utilizzo è il baseclass per il componente. componenti del generatore comunicano utilizzando liste, componenti filettati utilizzando Queue.Queues e procedimenti basati usando os.pipes.

Il motivo alla base di questo approccio è però di rendere più difficile per rendere difficile bug di debug. In threading - o qualsiasi concorrenza memoria condivisa che hai, il problema numero uno si faccia è rotto accidentalmente aggiornamenti dei dati condivisi. Utilizzando il messaggio che passa si elimina una classe di bug.

Se si utilizza threading a nudo e si blocca tutto il mondo si sta lavorando in genere sul presupposto che quando si scrive il codice che non fare errori. Mentre noi tutti aspiriamo a questo, è molto raro che accadrà. Avvolgendo il comportamento di blocco in un posto dove si semplificano le cose possono andare male. (Gestori di aiuto di contesto, ma non aiutano con gli aggiornamenti accidentali al di fuori del contesto del gestore)

Ovviamente non ogni pezzo di codice può essere scritto in forma di messaggio che passa e lo stile che è il motivo per cui Kamaelia dispone anche di un semplice software di memoria transazionale (STM), che è un'idea veramente pulito con un nome brutto condiviso - è più come controllo della versione per variabili - vale a dire controllare alcune variabili, aggiornarli e di impegnarsi di nuovo. Se si ottiene uno scontro di risciacquare e ripetere.

link pertinenti:

In ogni caso, spero che sia una soluzione utile. FWIW, la ragione principale dietro la messa a punto di Kamaelia è quello di rendere la concorrenza più sicuro e più facile da utilizzare nei sistemi di pitone, senza la coda scodinzolante del cane. (Vale a dire il grande secchio di componenti

Posso capire il motivo per cui l'altra risposta Kamaelia è stato modded giù, dal momento che anche a me sembra più simile a un annuncio di una risposta. Come l'autore di Kamaelia è bello vedere l'entusiasmo anche se spero che questo contiene un po 'di contenuti più rilevanti: -)

E questo è il mio modo di dire, si prega di prendere l'avvertenza che questa risposta è per definizione di parte, ma per me, lo scopo di Kamaelia è quello di cercare e avvolgere ciò che è IMO migliori pratiche. Io suggerirei di provare alcuni sistemi, e vedendo che funziona per voi. (Anche se questo non è appropriato per overflow dello stack, mi dispiace - io sono nuovo di questo forum: -)

Vorrei utilizzare le microfili (Tasklets) di Stackless Python, se ho dovuto usare le discussioni a tutti.

A tutto il gioco online (massivly multiplayer) è costruire intorno Stackless e il suo principio multithreading -. In quanto l'originale è solo a rallentare per la proprietà massivly multiplayer del gioco

Discussioni nel CPython sono ampiamente scoraggiate. Uno dei motivi è la GIL - un blocco interprete globale - che serializza filettatura per molte fasi dell'esecuzione. La mia esperienza è, che è davvero difficile creare applicazioni veloci in questo modo. Il mio esempio codifiche dove tutti più lento con filettatura -. Con un core (ma molte attese per l'ingresso dovrebbe aver fatto un po 'di prestazioni aumenta possibile)

Con CPython, piuttosto utilizzare i processi separati, se possibile.

Se davvero si vuole sporcarsi le mani, si può provare a utilizzando generatori a coroutine falsi . Probabilmente non è il più efficiente in termini di lavoro in questione, ma coroutine si offrono un controllo molto preciso della cooperativa multitasking piuttosto che il multitasking pre-emptive troverete altrove.

Un vantaggio che troverete è che in linea di massima, non sarà necessario serrature o mutex quando si utilizza il multitasking cooperativo, ma il vantaggio più importante per me era la velocità di commutazione quasi-zero tra "fili". Naturalmente, Stackless Python si dice che sia molto buono per quello pure; e poi c'è Erlang, se non lo fa sono di essere Python.

Probabilmente il più grande svantaggio in multitasking cooperativo è la generale mancanza di soluzione per bloccare I / O. E nei coroutine falsi, potrai anche incontrare il problema che non è possibile passare "fili" da qualsiasi cosa, ma il livello superiore dello stack all'interno di un thread.

Dopo aver presentato una domanda anche un po 'complesso, con coroutine falsi, avrete davvero iniziare ad apprezzare il lavoro che va nella pianificazione dei processi a livello di sistema operativo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top