2011-11-05 10 views
8

Nel seguente programma, quando accludo il processo a un elenco (una cosa apparentemente inutile), viene eseguito come previsto. Ma se rimuovo l'append, il distruttore dei processi viene chiamato molte volte prima che venga persino eseguito. Ci sono solo costruzioni n ma (n)(n+1)/2 (dove n è il numero di processi). Questo mi porta a credere che ogni processo venga copiato in ogni nuovo processo e quindi immediatamente distrutto. Forse è così che funziona il modulo multiprocessing. Ha senso, dal momento che ogni processo è un fork di quello attuale. Ma qual è il significato di aggiungere alla lista? Perché semplicemente questo smette di fare questo comportamento?Aggiungendo un processo a un elenco (ma senza fare nulla) altera il comportamento del programma

Ecco la prova e di campionamento in uscita:

import multiprocessing 

class _ProcSTOP: 
    pass 

class Proc(multiprocessing.Process): 

    def __init__(self, q, s): 
     s.i += 1 
     self._i = s.i 
     self._q = q 
     print('constructing:', s.i) 
     super().__init__() 

    def run(self): 
     dat = self._q.get() 

     while not dat is _ProcSTOP: 
      self._q.task_done() 
      dat = self._q.get() 

     self._q.task_done() 
     print('returning: ', self._i) 

    def __del__(self): 
     print('destroying: ', self._i) 



if __name__ == '__main__': 

    q = multiprocessing.JoinableQueue() 
    s = multiprocessing.Manager().Namespace() 
    s.i = 0 
    pool = [] 

    for i in range(4): 
     p = Proc(q, s) 
     p.start() 
     pool.append(p) # This is the line to comment 

    for i in range(10000): 
     q.put(i) 

    q.join() 

    for i in range(4): 
     q.put(_ProcSTOP) 

    q.join() 

    print('== complete') 

Esempio di output con accodamento:

constructing: 1 
constructing: 2 
constructing: 3 
constructing: 4 
returning: 3 
returning: 2 
== complete 
returning: 1 
returning: 4 
destroying: 4 
destroying: 3 
destroying: 2 
destroying: 1 

uscita campione senza accodamento:

constructing: 1 
constructing: 2 
constructing: 3 
destroying: 1 
constructing: 4 
destroying: 1 
destroying: 2 
destroying: 3 
destroying: 1 
destroying: 2 
returning: 1 
returning: 4 
returning: 2 
== complete 
returning: 3 
destroying: 1 
destroying: 3 
destroying: 2 
destroying: 4 
+0

Do you supponiamo che abbia qualcosa a che fare con la garbage collection? I sintomi indicano che è necessario mantenere un riferimento all'istanza della classe. – Dave

+0

@Dave. È un buon punto. Sospetto che tu sia sulla strada giusta. – tjm

risposta

1

L'aggiunta di un oggetto a un elenco impedirà l'eliminazione nei processi figli perché dopo la forking richiamerà "os._exit()" invece di cancellare l'intero stack

Il codice pertinente è in multiprocessing/forking.py (costruttore della popen, che si chiama il "p.start()")

self.pid = os.fork() 
if self.pid == 0: 
    if 'random' in sys.modules: 
     import random 
     random.seed() 
    code = process_obj._bootstrap() 
    sys.stdout.flush() 
    sys.stderr.flush() 
    os._exit(code) 

Dove _bootstrap messe a punto il nuovo processo e chiama "run" (codice è in multiprocessing/process.py)

Problemi correlati