如何正确使用SyncManager.Lock或Event?

时间:2017-07-27 05:39:13

标签: python multithreading

我无法正确使用SyncManager.Lock。我读了official doc,但它没有提供任何有效的例子。我也不知道如何正确使用SyncManager.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 个答案:

答案 0 :(得分:2)

我想出了一个解决方法。由于以下原因,请勿使用内置SyncManager.Lock()

  1. 每次创建一个新的Lock对象而不是共享。
  2. 它包裹了threading.Lock(), NOT multiprocess.Lock()。看起来它不能用于多处理!
  3. 解决方案是注册您自己的锁管理器:

    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)