为啥多处理锁获取不起作用?
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()
尝试将成功(如果至少存在一个这样的尝试),但没有定义哪一个。以上是关于为啥多处理锁获取不起作用?的主要内容,如果未能解决你的问题,请参考以下文章