为啥多处理锁获取不起作用?

Posted

技术标签:

【中文标题】为啥多处理锁获取不起作用?【英文标题】:Why doesn't multiprocessing Lock acquiring work?为什么多处理锁获取不起作用? 【发布时间】:2021-12-20 09:04:10 【问题描述】:

从这里的第一个答案中尝试了 2 个代码示例:Python sharing a lock between processes。结果是一样的。

import multiprocessing
import time
from threading import Lock


def target(arg):
    if arg == 1:
        lock.acquire()
        time.sleep(1.1)
        print('hi')
        lock.release()
    elif arg == 2:
        while True:
            print('not locked')
            time.sleep(0.5)


def init(lock_: Lock):
    global lock
    lock = lock_


if __name__ == '__main__':
    lock_ = multiprocessing.Lock()
    with multiprocessing.Pool(initializer=init, initargs=[lock_], processes=2) as pool:
        pool.map(target, [1, 2])

为什么会打印这段代码:

not locked
not locked
not locked
hi
not locked

改为

hi
not locked

【问题讨论】:

【参考方案1】:

好吧,将您的工作进程称为“1”和“2”。他们都开始了。 2 打印“未锁定”,休眠半秒,然后循环再次打印“未锁定”。但请注意,2 正在打印的内容与 lock 是否 锁定无关。代码 2 中的任何内容都不会执行甚至引用 lock,更不用说在 lock 上进行同步了。又过了半秒,2 醒来第三次打印“未锁定”,然后再次进入睡眠状态。

在此过程中,1 启动,获取锁,休眠 1.1 秒,然后打印“hi”。然后它释放锁并结束。在 1 开始打印“hi”时,2 已经打印了 3 次“未锁定”,并且距离其最近的半秒睡眠大约 0.1 秒。

打印“hi”后,2 将继续打印“未锁定”大约每秒两次。

所以代码似乎在做它被告知要做的事情。

不过,我无法猜测的是,您希望如何先看到“hi”,然后再看到“未锁定”。这将需要某种计时奇迹,其中 2 在 1 运行超过 1.1 秒之前根本没有开始执行。并非不可能,但极不可能。

变化

这是获得所需输出的一种方法,尽管我对您的意图做了很多猜测。

如果您不希望 2 在 1 结束之前开始,那么您必须强制。一种方法是让 2 开始时获取lock。这还需要保证lock 在任何工作人员开始之前处于获取状态。

所以在调用map() 之前获取它。那么让 1 获取它根本没有意义 - 1 可以立即开始,并在结束时释放它,以便 2 可以继续。

对代码的改动很少,但为了方便起见,我将其全部粘贴在这里:

import multiprocessing
import time
from threading import Lock

def target(arg):
    if arg == 1:
        time.sleep(1.1)
        print('hi')
        lock.release()
    elif arg == 2:
        lock.acquire()
        print('not locked')
        time.sleep(0.5)

def init(lock_: Lock):
    global lock
    lock = lock_


if __name__ == '__main__':
    lock_ = multiprocessing.Lock()
    lock_.acquire()
    with multiprocessing.Pool(initializer=init, initargs=[lock_], processes=2) as pool:
        pool.map(target, [1, 2])

【讨论】:

谢谢!我终于弄清楚锁是如何工作的。我以为当你调用 lock.acquire() 时,剩下的线程就被简单地阻塞了。 不——甚至没有关闭 ;-) 成功的.acquire() 的唯一效果是导致所有未来对.acquire() 的尝试被阻止,直到(如果有的话).release() 被调用。如果.release() 被调用,一个未完成的(被阻止的).acquire() 尝试将成功(如果至少存在一个这样的尝试),但没有定义哪一个。

以上是关于为啥多处理锁获取不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥多播不起作用?

css 为啥有时MARGIN 不起作用,

addeventlistener 监听storage为啥不起作用

为啥 jQuery 选择器在这里不起作用?

为啥background 不起作用

为啥获取外部 HTML 不起作用?