2015-02-01 3 views
7

Questo codice di multiprocessing funziona come previsto. Crea 4 processi Python e li utilizza per stampare i numeri da 0 a 39, con un ritardo dopo ogni stampa.Locks multiprocessing Python

import multiprocessing 
import time 

def job(num): 
    print num 
    time.sleep(1) 

pool = multiprocessing.Pool(4) 

lst = range(40) 
for i in lst: 
    pool.apply_async(job, [i]) 

pool.close() 
pool.join() 

Tuttavia, quando cerco di usare un multiprocessing.Lock per evitare che più processi da stampare sullo standard output, il programma appena esce immediatamente senza alcun output.

import multiprocessing 
import time 

def job(lock, num): 
    lock.acquire() 
    print num 
    lock.release() 
    time.sleep(1) 

pool = multiprocessing.Pool(4) 
l = multiprocessing.Lock() 

lst = range(40) 
for i in lst: 
    pool.apply_async(job, [l, i]) 

pool.close() 
pool.join() 

Perché l'introduzione di un multiprocessing.Lock rende questo codice non funzionante?

Aggiornamento: Funziona quando il blocco è dichiarato globalmente (dove ho fatto alcuni test non definitivi per verificare che il blocco funzioni), in contrapposizione al codice sopra il quale passa il blocco come argomento (la documentazione di multiprocessing di Python mostra serrature passate come argomenti). Il codice seguente ha un blocco dichiarato globalmente, anziché passare come argomento nel codice sopra.

import multiprocessing 
import time 

l = multiprocessing.Lock() 

def job(num): 
    l.acquire() 
    print num 
    l.release() 
    time.sleep(1) 

pool = multiprocessing.Pool(4) 

lst = range(40) 
for i in lst: 
    pool.apply_async(job, [i]) 

pool.close() 
pool.join() 

risposta

6

se si cambia pool.apply_async-pool.apply, si ottiene questa eccezione:

Traceback (most recent call last): 
    File "p.py", line 15, in <module> 
    pool.apply(job, [l, i]) 
    File "/usr/lib/python2.7/multiprocessing/pool.py", line 244, in apply 
    return self.apply_async(func, args, kwds).get() 
    File "/usr/lib/python2.7/multiprocessing/pool.py", line 558, in get 
    raise self._value 
RuntimeError: Lock objects should only be shared between processes through inheritance 

pool.apply_async lo sta semplicemente nascondendo. Detesto dire questo, ma l'utilizzo di una variabile globale è probabilmente il modo più semplice per il tuo esempio. Speriamo solo che lo velociraptors non ti prenda.

+0

Grazie! L'utilizzo dell'applicazione anziché di apply_async sembra un modo utile per eseguire il debug di questi problemi. –

+0

Sì, sembra un po 'sciocco che 'apply_async' non stampi nemmeno un messaggio di avviso. – matsjoyce

+0

Accetto, ma come soluzione alternativa è possibile utilizzare in Python 3 error_callback di apply_async. Soluzione alternativa per Python 2 -> http://stackoverflow.com/questions/27986885/error-callback-in-multiprocessing-pool-apply-async-in-python-2 – TitanFighter

3

Penso che il motivo è che la piscina multiprocessing utilizza pickle per trasferire oggetti tra i processi. Tuttavia, un Lock non può essere in salamoia:

>>> import multiprocessing 
>>> import pickle 
>>> lock = multiprocessing.Lock() 
>>> lp = pickle.dumps(lock) 
Traceback (most recent call last): 
    File "<pyshell#3>", line 1, in <module> 
    lp = pickle.dumps(lock) 
... 
RuntimeError: Lock objects should only be shared between processes through inheritance 
>>> 

Vedere il "Picklability" e "Meglio di ereditare di salamoia/deserializzare" sezioni di https://docs.python.org/2/library/multiprocessing.html#all-platforms