7

Il seguente codice, non viene stampato "here". Qual è il problema? L'ho provato su entrambe le mie macchine (Windows 7, Ubuntu 12.10), e http://www.compileonline.com/execute_python_online.php Non stampa "here" in tutti i casi.Lo script che utilizza il modulo multiprocessing non termina

from multiprocessing import Queue, Process 


def runLang(que): 
    print "start" 
    myDict=dict() 
    for i in xrange(10000): 
     myDict[i]=i 
    que.put(myDict) 
    print "finish" 


def run(fileToAnalyze): 
    que=Queue() 
    processList=[] 
    dicList=[] 
    langs= ["chi","eng"] 
    for lang in langs: 
     p=Process(target=runLang,args=(que,)) 
     processList.append(p) 
     p.start() 

    for p1 in processList: 
     p1.join() 

    print "here" 

    for _ in xrange(len(langs)): 
     item=que.get() 
     print item 
     dicList.append(item) 

if __name__=="__main__": 
    processList = [] 
    for fileToAnalyse in ["abc.txt","def.txt"]: 
     p=Process(target=run,args=(fileToAnalyse,)) 
     processList.append(p) 
     p.start() 
    for p1 in processList: 
     p1.join() 

risposta

13

Questo perché quando si put un sacco di voci in un multiprocessing.Queue, che alla fine ottiene tamponata nella memoria, una volta che il sottostante Pipe è pieno. Il buffer non verrà svuotato fino a quando qualcosa inizia a leggere dall'altra parte dello Queue, che consentirà allo Pipe di accettare più dati. A Process non può terminare fino a quando il buffer per tutte le sue istanze Queue non è stato completamente svuotato al sottostante Pipe. L'implicazione di ciò è che se si tenta di eseguire join un processo senza avere un altro processo/thread che chiama get sul suo Queue, è possibile che si verifichi un deadlock. Questo è mentioned in the docs:

Attenzione

Come accennato in precedenza, se un processo figlio ha messo gli elementi su una coda (e non ha usato JoinableQueue.cancel_join_thread), allora quel processo non terminerà fino a quando tutti gli articoli con buffer sono stati svuotati nella pipe .

Ciò significa che se si tenta di unirsi a tale processo, è possibile che si verifichi un deadlock a meno che non si sia sicuri che tutti gli elementi che sono stati messi in coda siano stati consumati. Allo stesso modo, se il processo figlio è non-demonico , il processo genitore potrebbe bloccarsi all'uscita quando tenta di unire tutti i suoi figli non demoniaci .

Si noti che una coda creata utilizzando un gestore non presenta questo problema.

È possibile risolvere il problema da non chiamare join fino a dopo si svuota il Queue nel genitore:

for _ in xrange(len(langs)): 
    item = que.get() 
    print(item) 
    dicList.append(item) 

# join after emptying the queue. 
for p in processList: 
    p.join() 

print("here")