Python compartiendo un locking entre procesos.

Estoy intentando usar una función parcial para que pool.map () pueda apuntar a una función que tenga más de un parámetro (en este caso, un objeto Lock ()).

Aquí está el código de ejemplo (tomado de una respuesta a una de mis preguntas anteriores):

from functools import partial def target(lock, iterable_item): for item in items: # Do cool stuff if (... some condition here ...): lock.acquire() # Write to stdout or logfile, etc. lock.release() def main(): iterable = [1, 2, 3, 4, 5] pool = multiprocessing.Pool() l = multiprocessing.Lock() func = partial(target, l) pool.map(func, iterable) pool.close() pool.join() 

Sin embargo, cuando ejecuto este código, me sale el error:

 Runtime Error: Lock objects should only be shared between processes through inheritance. 

¿Que me estoy perdiendo aqui? ¿Cómo puedo compartir el locking entre mis subprocesos?

Lo siento, debería haber captado esto en mi respuesta a tu otra pregunta. No puede pasar el multiprocessing.Lock normal. multiprocessing.Lock objetos a los métodos Pool agrupación, ya que no se pueden decapar. Hay dos maneras de evitar esto. Una es crear Manager() y pasar un Manager.Lock() :

 def main(): iterable = [1, 2, 3, 4, 5] pool = multiprocessing.Pool() m = multiprocessing.Manager() l = m.Lock() func = partial(target, l) pool.map(func, iterable) pool.close() pool.join() 

Esto es un poco pesado, sin embargo; el uso de un Manager requiere generar otro proceso para hospedar el servidor del Manager . Y todas las llamadas para acquire / release el locking deben enviarse a ese servidor a través de IPC.

La otra opción es pasar el multiprocessing.Lock() regular en el momento de la creación del Pool, usando el initializer kwarg. Esto hará que su instancia de locking sea global en todos los niños trabajadores:

 def target(iterable_item): for item in items: # Do cool stuff if (... some condition here ...): lock.acquire() # Write to stdout or logfile, etc. lock.release() def init(l): global lock lock = l def main(): iterable = [1, 2, 3, 4, 5] l = multiprocessing.Lock() pool = multiprocessing.Pool(initializer=init, initargs=(l,)) pool.map(target, iterable) pool.close() pool.join() 

La segunda solución tiene el efecto secundario de ya no requiere partial .

Aquí hay una versión (que usa Barrier lugar de Lock , pero se te ocurre la idea) que también funcionaría en Windows (donde la fork falta está causando problemas adicionales):

 import multiprocessing as mp def procs(uid_barrier): uid, barrier = uid_barrier print(uid, 'waiting') barrier.wait() print(uid, 'past barrier') def main(): N_PROCS = 10 with mp.Manager() as man: barrier = man.Barrier(N_PROCS) with mp.Pool(N_PROCS) as p: p.map(procs, ((uid, barrier) for uid in range(N_PROCS))) if __name__ == '__main__': mp.freeze_support() main()