2017-07-27 17 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)