如何正确使用SyncManager.Lock或Event? [英] How to use SyncManager.Lock or Event correctly?

查看:124
本文介绍了如何正确使用SyncManager.Lock或Event?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在正确使用SyncManager.Lock时遇到了麻烦.我阅读了官方文档,但是没有提供有效的示例.我也不知道如何正确使用SyncManager.Event.

I'm having trouble using SyncManager.Lock correctly. I read the official doc, but it offers no working example. I also have no idea how to use SyncManager.Event correctly.

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

Below is the minimal code to illustrate my problem. client1 and client2 both need to update a shared object Struct. However, I want client1 to acquire the lock first, update Struct, and then pass control to client2. If you run the code below as-is, the print statements are all mixed up.

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]

推荐答案

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

I figured out a workaround. Don't use the builtin SyncManager.Lock() for the following reasons:

  1. 它每次都在创建一个新的Lock对象,而不是共享.
  2. 它环绕threading.Lock(), multiprocess.Lock().看起来不适用于多处理!
  1. It's creating a new Lock object every time instead of sharing.
  2. It wraps around threading.Lock(), NOT multiprocess.Lock(). Looks like it doesn't work with multiprocessing!

解决方案是注册您自己的锁管理器:

Solution is to register your own lock manager:

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)

这篇关于如何正确使用SyncManager.Lock或Event?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆