¿Cómo usar SyncManager.Lock o Event correctamente?

Estoy teniendo problemas para usar SyncManager.Lock correctamente. Leí el documento oficial , pero no ofrece ningún ejemplo de trabajo. Tampoco tengo idea de cómo usar SyncManager.Event correctamente.

A continuación se muestra el código mínimo para ilustrar mi problema. client2 y client2 necesitan actualizar un objeto compartido Struct . Sin embargo, quiero que client1 adquiera primero el locking, actualice Struct y luego pase el control a client2 . Si ejecuta el código a continuación tal como está, las declaraciones de print se mezclan.

 import multiprocessing as mp from multiprocessing.managers import SyncManager import time class Struct: def __init__(self): self.a = [] def update(self, x, y): self.a.append(x ** 2) def get(self): return self.a class Server(SyncManager): pass global_S = Struct() Server.register('Struct', lambda: global_S) def server_run(): print('Server starting ...') manager = Server(('localhost', 8080), authkey=b'none') manager.get_server().serve_forever() def client_run(name, x, y, wait): server_proc = Server(('localhost', 8080), authkey=b'none') server_proc.connect() S = server_proc.Struct() with server_proc.Lock(): for i in range(5): S.update(x+i, y+i) print(name, S.get()) time.sleep(wait) server = mp.Process(target=server_run) server.daemon = True client1 = mp.Process(target=client_run, args=('c1', 3,7, 1)) client2 = mp.Process(target=client_run, args=('c2', 100,120, .6)) server.start() time.sleep(0.3) # wait for server to spawn up client1.start() time.sleep(0.3) client2.start() client1.join() client2.join() 

Salida de muestra:

 Server starting ... c1 [9] c2 [9, 10000] c2 [9, 10000, 10201] c1 [9, 10000, 10201, 16] c2 [9, 10000, 10201, 16, 10404] c1 [9, 10000, 10201, 16, 10404, 25] c2 [9, 10000, 10201, 16, 10404, 25, 10609] c2 [9, 10000, 10201, 16, 10404, 25, 10609, 10816] c1 [9, 10000, 10201, 16, 10404, 25, 10609, 10816, 36] c1 [9, 10000, 10201, 16, 10404, 25, 10609, 10816, 36, 49] 

Me di cuenta de una solución. No use SyncManager.Lock() por los siguientes motivos:

  1. Se está creando un nuevo objeto de locking cada vez en lugar de compartir.
  2. Se ajusta a los hilos. Bloqueo (), NO multiproceso. Bloqueo (). Parece que no funciona con multiprocesamiento!

La solución es registrar su propio administrador de locking:

 from multiprocessing.managers import BaseManager, AcquirerProxy global_lock = mp.Lock() def get_lock(): print('getting global_lock') return global_lock Server.register('Lock', get_lock, AcquirerProxy)