使用POSIX文件锁定确保您的代码不会在多个进程中进行并发执行。
项目描述
这是一个简单的Python 3.4+模块,用于确保您的代码不会在多个进程中并发执行,使用POSIX文件锁定。
可以使用with语法或作为装饰器轻松获取锁。
为什么?
如果您有长时间运行的过程,如果并发执行将导致损坏,那么这个包就是为您准备的。您可以在执行备份、数据库迁移或其他需要在中断时中止的长运行脚本中使用它。
内部工作原理
该模块使用POSIX文件锁定和PID文件
选择一个文件来存储锁信息,通常是/var/lock/py_exclusivelock_yournamehere.lock,称为锁文件,基于您提供的名称。在用作文件名之前,名称会被清理。
如果锁文件已存在并且它包含正在运行的过程的PID(包括当前进程),则会抛出CannotAcquireLock异常。
否则,锁文件将被创建(或覆盖),并将此进程的整数进程ID写入文件。使用POSIX文件锁定(lockf)和以O_EXCL方式打开来防止竞态条件。
当with语句块或装饰函数退出时,锁定文件会被删除。或者在程序退出时,如果使用.forever()(见下文)。
如何使用它
首先安装此包
pip3 install exclusiveprocess
然后在Python文件中导入该包
from exclusiveprocess import Lock, CannotAcquireLock
您可以在with语句中使用它
try: with Lock(name="myprocess"): print("This block cannot be executed concurrently!") except CannotAcquireLock: print("Well, that's bad.")
或者作为装饰器
# lock name chosen based on __file__ @Lock def myfunc(): print("This function cannot be executed concurrently!") # lock name is "myprocess" @Lock(name="myprocess") def myfunc(): print("This function cannot be executed concurrently!")
名称由您决定。锁是针对名称的。名称是系统全局的(与文件系统一样全局)。
还有一些方便的功能可以帮助您锁定整个程序。
name参数是可选的,默认值为调用Lock函数的模块的文件名(即您的Python源文件),使用inspect.stack(),使得Lock对所有应用程序的调用都是自动排他的。
当您将可选的die关键字参数设置为True时,如果无法获取锁,Lock会在STDERR上打印错误信息并立即以退出代码1退出进程,而不是抛出异常。
您可以使用.forever()而不是with或装饰器语法来获取锁,在这种情况下,锁将在程序退出时使用atexit释放。
通过这些功能,您可以在程序开始处放置以下行来使整个程序独占使用
# At program start. Lock(die=True).forever() # program exits here if lock could not be acquired
如果同时运行两个这样的程序,您将在STDERR上看到
Another '/home/user/your_script.py' process is already running (pid 27922).
高级
如果您想查看锁定文件存储的位置,可以捕获with对象
with Lock(name="test1") as lock: print(lock.lockfile) # outputs: /var/lock/py_exclusivelock_test1.lock
Lock类会将每次获取和释放锁都记录到logging.info。