Linux 环境下 Python 中的系统互斥锁

有没有什么简单的方法可以在 Linux 上的 Python 中实现系统范围的互斥锁?我所说的“系统范围”是指互斥对象将由一组 Python 程序使用; 这与传统的互斥对象形成了对比,传统的互斥对象由同一进程中的一组 丝线使用。

编辑: 我不确定 Python 的 multiprocessing包是否是我所需要的。例如,我可以在两个不同的解释器中执行以下操作:

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

当我在两个不同的解释器中同时执行这些命令时,我希望其中一个命令挂起。相反,两者都没有挂起; 它们似乎没有获取相同的互斥对象。

40385 次浏览

POSIX 标准指定了可用于此目的的进程间信号量

Python 中的 multiprocessing模块是基于这个 API 和其他 API 构建的。特别是,multiprocessing.Lock提供了一个跨进程的“互斥”。http://docs.python.org/library/multiprocessing.html#synchronization-between-processes

编辑回答编辑过的问题:

在概念验证中,每个过程都是构造一个 Lock()。所以你有两把独立的锁。这就是为什么两个进程都不等待。您需要在进程之间共享相同的锁。我在 multiprocessing文档中链接到的部分解释了如何做到这一点。

Unix 的“传统”解决方案是使用文件锁。您可以使用 lockf(3)锁定文件的某些部分,这样其他进程就无法编辑它; 一种非常常见的滥用是使用它作为进程之间的互斥锁。Python 等价物是 Fcntl.lockf

传统上,您将锁定进程的 PID 写入锁定文件,以便在持有锁定时由于进程死亡而导致的死锁是可识别和可修复的。

这将得到您想要的结果,因为您的锁位于全局名称空间(文件系统)中,并且所有进程都可以访问它。这种方法还有一个好处,非 Python 程序可以参与您的锁定。缺点是您需要一个位置来存放这个锁文件; 此外,有些文件系统实际上不能正确锁定,因此存在无声无息地无法实现排除的风险。有得必有失。

对于支持绝对独立进程同步的系统范围的互斥锁(例如,对不属于同一进程树的 INCLUDE Linux 进程) ,只需使用 Fcntl 群。我认为使用 Linux’/run/shm 文件夹下的内存文件可能会使它执行得更快。

详见 给你

试试 锁定库:

from ilock import ILock


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

只要在列表中添加一个类,就可以看到 Posx _ ipc库,它有一个 Semaphore类。

计数为1的 信号灯可以用作 互斥。 为了完成这三个线程,SystemEvent 系统事件库利用了 posix_ipc并提供了一个 事件

我还要指出,这也没有投票你的硬盘驱动器!

我的答案与其他答案重叠,但只是添加一些人们可以复制粘贴,我经常这样做。

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 项目。我不确定是否需要 find ()调用,但它们之所以存在,是因为 WindowsAPI 锁定了文件中的特定位置。如果您不使用该文件的任何其他锁定,您可能会删除寻找。

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()