Python:锁定目录
Posted
技术标签:
【中文标题】Python:锁定目录【英文标题】:Python: Lock directory 【发布时间】:2019-03-09 15:54:40 【问题描述】:AFAIK 此代码可用于锁定目录:
class LockDirectory(object):
def __init__(self, directory):
assert os.path.exists(directory)
self.directory = directory
def __enter__(self):
self.dir_fd = os.open(self.directory, os.O_RDONLY)
try:
fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError as ex:
if ex.errno != errno.EAGAIN:
raise
raise Exception('Somebody else is locking %r - quitting.' % self.directory)
def __exit__(self, exc_type, exc_val, exc_tb):
self.dir_fd.close()
但是根据这个问题的答案锁定一个目录是不可能的:Python: Lock a directory
上面的代码有什么问题?
我只需要支持当前的linux版本。没有 Windows、Mac 或其他 unix。
【问题讨论】:
你自己的python进程是唯一对目录进行操作的候选吗? @FlyingTeller 有另一个进程将文件放入此目录,但这不需要锁定。只有消耗数据的python脚本需要锁定。 如果它在同一个进程中,为什么不使用“is_running”标志,这样如果当前进程没有完成,你就不会触发下一个进程? 问题是“如何锁定目录?”答案是“你不能,创建一个象征着锁定目录的文件” @Jean-FrançoisFabre Cron 每 N 分钟启动一次进程。您建议使用“is_running”标志。这就是为什么我要锁定脚本运行的目录。 【参考方案1】:我稍微修改一下你的代码,像大多数上下文管理一样添加return self
,然后使用dup()
,第二个上下文管理将失败。解决方案很简单,取消注释fcntl.flock(self.dir_fd,fcntl.LOCK_UN)
用于打开文件的模式与flock无关。
而且你不能在 NFS 上蜂拥而至。
import os
import fcntl
import time
class LockDirectory(object):
def __init__(self, directory):
assert os.path.exists(directory)
self.directory = directory
def __enter__(self):
self.dir_fd = os.open(self.directory, os.O_RDONLY)
try:
fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError as ex:
raise Exception('Somebody else is locking %r - quitting.' % self.directory)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# fcntl.flock(self.dir_fd,fcntl.LOCK_UN)
os.close(self.dir_fd)
def main():
with LockDirectory("test") as lock:
newfd = os.dup(lock.dir_fd)
with LockDirectory("test") as lock2:
pass
if __name__ == '__main__':
main()
【讨论】:
太棒了。有没有人从这个在 github+pypi 上制作一个小 Python 库很有趣?【参考方案2】:如果您只需要一个 read 锁,那么您的代码中只有一个小错误。在目录上获得读锁是完全可行的。
您需要更改您的__exit__
函数以使用os.close()
来关闭文件描述符;文件描述符只是一个整数,整数没有.close()
方法:
def __exit__(self, exc_type, exc_val, exc_tb):
os.close(self.dir_fd)
对于那些认为你做不到的人来说,通常的困惑是那些尝试过 open()
函数的人。 Python 不会让您使用该函数打开目录节点,因为为目录创建 Python 文件对象是没有意义的。或者您可能假设您希望操作系统通过锁定强制访问目录(而不是一组协作进程同意在尝试访问之前首先获得的建议锁定)。
所以,不,如果您想要的只是一个咨询锁,那么代码没有任何问题,并且仅适用于 Linux 就可以了。
我会从代码中删除directory
的区别。该锁将在您具有读取权限的任何路径上工作。它不是目录独有的。
锁定目录的缺点是它没有给您一个存储锁定元数据的地方。虽然lsof
可以为您提供锁的当前所有者的 PID,但您可能希望与锁通信一些其他信息以帮助排除故障或自动开锁。 .lock
文件或符号链接可让您记录其他信息。例如,Mercurial 将使用主机名、PID 命名空间标识符(仅限 Linux)和目标名称中的 PID 创建一个符号链接;您可以原子地创建这样的符号链接,而将数据写入文件需要在临时名称下创建一个文件,然后重命名。
【讨论】:
【参考方案3】:我在这里找到了答案:Python: Lock directory
可以用这个来锁定目录:
fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
当然这是一个锁,玩这个游戏的每个代码都需要先检查。
AFAIK 这被称为“咨询锁”。
【讨论】:
你不需要再保留这个了。我合并了问题。请不要再问这样的重复问题。 @YvetteColomb 如果我再次这样做会怎样? 这不是可能发生的最糟糕的事情,这是我们不鼓励的事情。它为人们不得不关闭它们创造了更多的工作。如果这是一个持续的习惯,它可能会导致纪律处分,但这是在极少数和持续存在的情况下。【参考方案4】:我建议您使用简单的锁定文件。正如评论 (How to lock a directory between python processes in linux?) 中的问题所暗示的那样,目录 没有锁定机制,而不是文件。 锁定文件在 Linux 上左右使用,它们非常透明且易于调试,所以我就这么做了。 不过,我正在等待接受挑战!
【讨论】:
目录支持咨询锁定就好了,其他答案是完全错误的。你所需要的只是一个文件句柄,低级的os.open()
调用可以让你打开一个目录文件句柄就好了。以上是关于Python:锁定目录的主要内容,如果未能解决你的问题,请参考以下文章