如果非阻塞或超时,则获取多处理。在 with 语句中锁定

发布于 2025-01-10 08:41:31 字数 872 浏览 0 评论 0原文

使用普通的 multiprocessing.Lock (或 threading.Lock),您可以将以下代码简化为:

lock = multiprocessing.Lock()
lock.acquire()

try:
    ...
finally:
    lock.release()

然而

with lock:
    ...

,当我想传递一些内容时,我仍然可以使用上下文管理器吗? lock.acquire(...) 的参数,例如 block=timeout=?例如,我有这样的代码:

lock_success = lock.acquire(block=False)

if not lock_success:
    return

try:
    ...
finally:
    lock.release()

我没有找到将此参数传递给上下文管理器的方法(因为它位于 acquire 调用中,而不是构造函数中)。

(这个想法是,如果无法获取锁,with 块将被跳过。)

类似地,threading.Lock 也提供了类似的 API。

With a normal multiprocessing.Lock (or threading.Lock) you can simplify the following code:

lock = multiprocessing.Lock()
lock.acquire()

try:
    ...
finally:
    lock.release()

into:

with lock:
    ...

However, can I still use a context manager when I want to pass some arguments to lock.acquire(...), such as block= or timeout=? For example, I have code like this:

lock_success = lock.acquire(block=False)

if not lock_success:
    return

try:
    ...
finally:
    lock.release()

I don't see a way to pass this argument to the context manager (since it's in the acquire call and not the constructor).

(The idea is that the with-block would get skipped if the lock cannot be acquired.)

Analogously for threading.Lock which provides a similar API.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

另类 2025-01-17 08:41:31

太长了;您不能使用内置的锁定上下文管理器,但它仍然可以相当干净地完成。

它几乎可以工作,因为 Lock.__enter__() 确实返回了从调用 acquire() 中返回的值,这应该是获取锁成功或失败的布尔值。

l = Lock()
with l as success:
    if success:
        print("run some code")
    else:
        print("skip the code")

然而令人沮丧的是,无法将参数传递给内部调用acquire(硬编码参数此处)。我建议您编写自己的上下文管理器来解决这个问题,因为它非常简单:

from multiprocessing import Lock
from contextlib import contextmanager

@contextmanager
def get_lock(lock, block=True, timeout=None):
    held = lock.acquire(block=block, timeout=timeout)
    try:
        yield held
    finally:
        if held:
            lock.release()

#### example usage ####

l = Lock()
#lock should be acquired so success == True
with get_lock(l) as success:
    if success:
        print("run some code")
    else:
        print("skip the code")

l.acquire()
#lock won't be acquired and block will proceed after timeout
#use the value of success to determine what to do
with get_lock(l, True, 3) as success:
    if success:
        print("run some code")
    else:
        print("skip the code")

l.release()

TLDR; you cannot use the built-in lock context manager, but it can still be done fairly cleanly.

It could almost work because Lock.__enter__() does return the value returned from the call to acquire() which should be the boolean success or failure of getting the lock.

l = Lock()
with l as success:
    if success:
        print("run some code")
    else:
        print("skip the code")

Frustratingly however it is not possible to pass arguments to the internal call to acquire (hardcoded args here). I would recommend writing your own context manager to solve this, as it is quite straightforward:

from multiprocessing import Lock
from contextlib import contextmanager

@contextmanager
def get_lock(lock, block=True, timeout=None):
    held = lock.acquire(block=block, timeout=timeout)
    try:
        yield held
    finally:
        if held:
            lock.release()

#### example usage ####

l = Lock()
#lock should be acquired so success == True
with get_lock(l) as success:
    if success:
        print("run some code")
    else:
        print("skip the code")

l.acquire()
#lock won't be acquired and block will proceed after timeout
#use the value of success to determine what to do
with get_lock(l, True, 3) as success:
    if success:
        print("run some code")
    else:
        print("skip the code")

l.release()
茶底世界 2025-01-17 08:41:31

我怀疑这是不可能的,因为 Python 中上下文管理器的设计方式不同。上下文管理器 (CM) 发生的情况是:

with CM:
    ...
  • CM 的 __enter__ 方法被调用
  • with 内部的块被运行
  • CM 的 __exit__ 方法是因此

,没有办法“跳过”with 块的内部,所以我想这解释了 Lock 类的设计。尽管有一些黑暗魔法方法解决这个问题(应该避免)。

My suspicion is that this is not possible because of how context managers are designed in Python. What happens with a context manager (CM) is:

with CM:
    ...
  • The CM's __enter__ method is called
  • The block inside of with is run
  • The CM's __exit__ method is called

Thus there is no way to "skip" the inside of the with-block, so I guess this explains the design of the Lock class. Although there are some dark magic ways around that (which should be avoided).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文