2017-07-27 16 views
1

我无法正确使用SyncManager.Lock。我读了official doc,但它没有提供任何工作示例。我也不知道如何正确使用SyncManager.Event如何正确使用SyncManager.Lock或Event?

下面是说明我的问题的最小代码。 client1client2都需要更新共享对象Struct。但是,我想要client1先获取锁,更新Struct,然后将控制权传递给client2。如果按照原样运行代码,则print语句全部混淆在一起。

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() 

输出示例:

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] 

回答

1

我想出了一个解决方法。不要使用有以下原因内建SyncManager.Lock()

  1. 它创建一个新的锁定对象每次而不是共享。
  2. 它围绕threading.Lock(),NOT multiprocess.Lock()。看起来它不适用于多处理!

解决办法就是注册自己的锁管理器:

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)