Linux下Python的系统级互斥锁

77 投票
6 回答
46687 浏览
提问于 2025-04-16 22:49

有没有简单的方法可以在Linux上为Python创建一个系统级的互斥锁?这里的“系统级”是指这个互斥锁会被一组Python 进程使用;这和传统的互斥锁不同,后者是用于同一个进程内的一组线程

补充说明:我不太确定Python的multiprocessing包是否适合我的需求。例如,我可以在两个不同的解释器中执行以下命令:

from multiprocessing import Lock
L = Lock()
L.acquire()

当我在两个不同的解释器中同时执行这些命令时,我希望其中一个会被挂起。但实际上,两个都没有挂起;看起来它们并没有获取到同一个互斥锁。

6 个回答

21

可以试试这个叫做 ilock 的库:

from ilock import ILock

with ILock('Unique lock name'):
    # The code should be run as a system-wide single instance
    ...
24

我的回答和其他人的有些重叠,但我想补充一些大家可以直接复制粘贴的内容,我经常会这样做。

class Locker:
    def __enter__ (self):
        self.fp = open("./lockfile.lck")
        fcntl.flock(self.fp.fileno(), fcntl.LOCK_EX)

    def __exit__ (self, _type, value, tb):
        fcntl.flock(self.fp.fileno(), fcntl.LOCK_UN)
        self.fp.close()

然后可以这样使用:

print("waiting for lock")
with Locker():
    print("obtained lock")
    time.sleep(5.0)

为了测试,可以先运行 touch lockfile.lck,然后在两个或更多不同的终端中(从同一个目录)运行上面的代码。

更新:smwikipedia提到我的解决方案是针对Unix系统的。最近我需要一个可以在不同系统上使用的版本,于是想出了以下这个,灵感来自一个随机的GitHub项目。我不确定seek()调用是否必要,但它们在这里是因为Windows的API会锁定文件中的特定位置。如果你只是用这个文件来锁定,可能可以去掉这些seek。

if os.name == "nt":
    import msvcrt

    def portable_lock(fp):
        fp.seek(0)
        msvcrt.locking(fp.fileno(), msvcrt.LK_LOCK, 1)

    def portable_unlock(fp):
        fp.seek(0)
        msvcrt.locking(fp.fileno(), msvcrt.LK_UNLCK, 1)
else:
    import fcntl

    def portable_lock(fp):
        fcntl.flock(fp.fileno(), fcntl.LOCK_EX)

    def portable_unlock(fp):
        fcntl.flock(fp.fileno(), fcntl.LOCK_UN)


class Locker:
    def __enter__(self):
        self.fp = open("./lockfile.lck")
        portable_lock(self.fp)

    def __exit__(self, _type, value, tb):
        portable_unlock(self.fp)
        self.fp.close()
48

在“传统”的Unix系统中,解决这个问题的方法是使用文件锁。你可以用 lockf(3) 来锁定文件的某些部分,这样其他程序就不能编辑这些部分了;很多时候,人们会把它当作进程之间的互斥锁来使用。在Python中,类似的功能可以通过 fcntl.lockf 来实现。

通常情况下,你会把锁定进程的PID(进程ID)写入锁文件,这样如果进程在持有锁的时候崩溃了,就能识别并解决死锁问题。

这样做可以满足你的需求,因为这个锁是在一个全局的命名空间中(也就是文件系统),所有进程都能访问到。这个方法的好处是,非Python的程序也可以参与到你的锁定机制中。不过,缺点是你需要有一个地方来存放这个锁文件;而且,有些文件系统并不能正确地实现锁定,所以可能会出现锁定失败的情况。总的来说,有得有失。

撰写回答