2015-05-18 14 views
7

Se utilizzo Queue.Queue, la mia funzione read() non funziona, perché? Ma se io uso multiprocessing.Queue, funziona bene:multiprocessing.Queue e Queue.Queue sono diversi?

from multiprocessing import Pool, Process, Queue 
import os, time 
# from Queue import Queue 

def write(q): 
    for v in ['A', 'B', 'C']: 
     print 'Put %s to queue ' % v 
     q.put_nowait(v) 
     time.sleep(0.2) 

def read(q): 
    while 1: 
     if not q.empty(): 
      v = q.get(True) 
      print "Get %s from queue" % v 
      time.sleep(0.2) 
     else: 
      break 

if __name__ == '__main__': 
    q = Queue() 
    pw = Process(target=write, args=(q,)) 
    pr = Process(target=read, args=(q,)) 
    pw.start() 
    pw.join() 

    pr.start() 
    pr.join() 

    print "all done..." 
+2

Pensateci in questo modo: se non fossero diversi, perché esisterebbe "multiprocessing.Queue"? Il suo scopo è darti un oggetto 'queue.Queue' che funzioni anche tra processi separati. – abarnert

risposta

19

Queue.Queue è solo una coda in memoria che sa come trattare con più thread utilizzando allo stesso tempo. Funziona solo se sia il produttore che il consumatore si trovano nello stesso processo.

Una volta acquisiti in processi di sistema separati, che cos'è la libreria multiprocessing, le cose sono un po 'più complicate, perché i processi non condividono più la stessa memoria. È necessario un qualche tipo di metodo di comunicazione tra processi per consentire ai due processi di comunicare tra loro. Può essere una memoria condivisa, una pipe o un socket, o forse qualcos'altro. Questo è ciò che fa multiprocessing.Queue. Usa i tubi per fornire un modo per comunicare tra due processi. Accade semplicemente di implementare la stessa API di Queue.Queue, perché molti programmatori Python hanno già familiarità con esso.

Nota anche che nel modo in cui stai usando la coda, hai una condizione di competizione nel tuo programma. Pensa a cosa succede se il processo scrive nella coda subito dopo aver chiamato q.empty() nel processo read. Normalmente dovresti aggiungere qualche elemento speciale alla coda (ad esempio None) che significherebbe che il consumatore può fermarsi.

+0

Ho trovato q.empty() per Multiprocessing.Queue essere * estremamente * inaffidabile. È sbagliato più spesso di quanto sia giusto, francamente. Nemmeno un problema relativo alla condizione della gara: è possibile che Process A inserisca qualcosa nella coda quando Process B sta dormendo, e in seguito invoca empty() da Process B - segnala vuoto, indipendentemente dalla durata dell'attesa. Un'opzione molto migliore è verificare se qsize()> 0 - che non è perfetto, ma * molto * più coerente in modo coerente. –

+0

Un FYI riguardante la multiprocessing.Queue (come differenza comportamentale su queue.Queue): i dati inseriti nella coda * devono * essere letti. Se un processo scrive in una coda e successivamente termina, non si interromperà fino a quando un altro processo non prenderà l'oggetto della coda. –

Problemi correlati