Python中是不是有带键的同步锁?

Posted

技术标签:

【中文标题】Python中是不是有带键的同步锁?【英文标题】:Is there a synchronization lock with key in Python?Python中是否有带键的同步锁? 【发布时间】:2021-10-28 00:12:31 【问题描述】:

我需要一个 Lock 对象,类似于multiprocessing.Manager().Lock() 只允许从实际获得它的进程中释放。

我的手动实现类似于以下内容:

class KeyLock:
    def __init__(self):
        self._lock = Lock()
        self._key: Optional[str] = None

    def acquire(self, key: 'str', blocking: bool = True, timeout: float = 10.0) -> bool:
        if self._lock.acquire(blocking=blocking, timeout=timeout):
            self._key = key
            return True
        return False

    def release(self, key, raise_error: bool = False) -> bool:
        if self._key == key:
            self._lock.release()
            return True
        if raise_error:
            raise RuntimeError(
                'KeyLock.released called with a non matchin key!'
            )
        return False

    def locked(self):
        return self._lock.locked()

要创建此锁的实例并从多个进程中使用它,我将使用自定义管理器类:

class KeyLockManager(BaseManager):
    pass


KeyLockManager.register('KeyLock', KeyLock)

manager = KeyLockManager()
manager.start()
lock = manager.KeyLock()

然后我可以从不同的过程中做:

lock.acquire(os.getpid())
# use shared ressource
...
lock.release(os.getpid())

这按预期工作,但对于一项相对简单的任务来说似乎是一项相当大的努力。 所以我想知道是否有更简单的方法可以做到这一点?

【问题讨论】:

如果您可以将 body 转换为函数,我创建了一个可以帮助您的装饰器,请参阅 here 【参考方案1】:

multiprocessing.RLock,根据定义只能由获取它的进程释放。或者您可能会考虑类似以下的情况,其中 Lock 实例被封装,并且仅用作上下文管理器,除非您已获取它,否则无法释放它,除非您违反封装。当然,可以为类添加额外的保护,以防止尝试违反封装并访问Lock 实例本身。当然,在您的实现中,也可能总是违反封装,因为可以获取其他进程的 pid。所以我们假设所有用户都遵守规则。

from multiprocessing import Lock

class KeyLock:
    def __init__(self):
        self.__lock = Lock()

    def __enter__(self):
        self.__lock.acquire()
        return None

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.__lock.release()
        return False

# Usage:

key_lock = KeyLock()
with key_lock:
    # do something
    ...

【讨论】:

嗯-谢谢@Booboo。 RLock 根据问题的需要处理锁的所有权。问题是锁将在服务器进程中“活动”,由 Manager() 对象控制。获取锁总是通过代理对象发生,因此锁的所有者可能总是来自服务器进程。 我主张“仅在“with”上下文中使用锁”解决方案。普通锁已经这样做了,除非您不一致,否则我看不出这会如何失败,并且有时会在“with”上下文之外释放锁。确实,使用 RLock 的代理可能不会执行您想要的操作,因为实际的锁对象只存在于一个进程中,而该进程只能继续获取相同的锁。然而,一个普通的 Lock 应该能够完全按照您的要求做,而无需修改。

以上是关于Python中是不是有带键的同步锁?的主要内容,如果未能解决你的问题,请参考以下文章

python--同步锁/递归锁/协程

Python学习第47天(递归锁同步对象信号量)

Java:wait()是不是从同步块中释放锁

python-并发并行同步异步同步锁

python 同步异步,并发并行,同步锁

python thread模块 锁 同步锁