Python 如何在获取独占锁时打开(如果不存在则创建)文件

Python 如何在获取独占锁时打开(如果不存在则创建)文件,python,linux,multithreading,locking,Python,Linux,Multithreading,Locking,在python 2.7中,是否可能(以及如何)在单个原子(无竞争)操作中: 打开一个文件 如果它不存在,请创建并打开它 获取文件的独占锁(其他进程无法打开或删除该文件) Context:我有一个python程序,它将获取给定URL/md5列表的文件;如果列表中的某个文件存在并且它的md5匹配,则会跳过该文件。如果没有,它将被下载。现在,该程序可能有多个实例处理可能重叠的不同列表 这几乎是我需要做的,但在我的情况下,我需要以任何一种方式锁定文件以检查其md5,同时防止其他人这样做。而且,

在python 2.7中,是否可能(以及如何)在单个原子(无竞争)操作中:

  • 打开一个文件
    • 如果它不存在,请创建并打开它
  • 获取文件的独占锁(其他进程无法打开或删除该文件)

Context:我有一个python程序,它将获取给定URL/md5列表的文件;如果列表中的某个文件存在并且它的md5匹配,则会跳过该文件。如果没有,它将被下载。现在,该程序可能有多个实例处理可能重叠的不同列表

这几乎是我需要做的,但在我的情况下,我需要以任何一种方式锁定文件以检查其md5,同时防止其他人这样做。而且,在操作之前,我不需要知道文件是否存在;如果它是刚刚创建的文件将是空的,它的md5将不匹配,因此它将被下载

我专门在Linux上使用这个程序,但欢迎使用跨平台解决方案


编辑: 最后,我通过以下方式解决了我的问题:

  • 以a+b模式打开文件(不是原子模式,如果不存在则创建)
  • 尝试以独占方式锁定文件(建议):
    • 如果成功,请存档
    • 如果失败,则假定其他人正在处理该文件并跳到下一个。在没有更多要处理的文件后,请回来检查锁定文件的人是否正确完成了工作

目前,单个原子步骤不支持所需的操作,但也不需要。

这是不可能的,至少符合以下条件:

  • mv-T
    自动将
    的目标更改为
    指向的目录,并且 部署新代码时必不可少。更新日期2010-01-06:两者 操作数是符号链接。(所以这不是一个系统调用,它仍然是 一位读者指出,
    ln-Tfs
    在没有第二个符号链接的情况下完成相同的事情。补充 2010-01-06. 删除2010-01-06:strace(1)显示
    ln-Tfs
    实际上调用符号链接(2)、取消链接(2)和 再次使用符号链接(2),取消其在此页面的资格
    mv-T
    最后调用rename(2),它可以 自动替换
    。注意事项2013-01-07:这不是 适用于Mac OS X,其mv(1)不调用重命名(2)。mv(1)
  • link(oldpath,newpath)
    创建一个名为newpath的新硬链接,指向与oldpath相同的inode,并将链接计数增加 一个。如果newpath已经存在,则此操作将失败,错误代码为EEXIST 存在,使其成为锁定文件的有用机制 所有线程或进程都可以约定名称newpath。我 对于整个文件锁定,更喜欢这种技术,因为锁是 ls(1)可见。链接(2)
  • symlink(oldpath,newpath)
    的操作与link(2)非常相似,但在新的inode处创建符号链接,而不是到 同样的inode。符号链接可以指向目录,其中包含硬链接 不能,这使它们在锁定整个对象时与链接(2)非常相似 目录。如果使用newpath,则此操作将失败,错误代码为EEXIST 已经存在,这是一个完美的类比链接(2)的工作 对于目录也是如此。注意目标inode的符号链接 已删除(“悬挂”符号链接)-打开(2)将失败 错误代码为enoint。应该提到的是,索引节点是一个 有限资源(此特定机器有1245184个索引节点)。 符号链接(2)。新增日期:2010-01-07
  • 重命名(oldpath,newpath)
    可以自动更改路径名,前提是oldpath和newpath位于同一文件系统上。这将 如果oldpath不存在,则失败,错误代码为enoint,启用 进程间锁定很像上面的链接(oldpath、newpath)。我发现 当有问题的文件被删除时,这种技术更自然 后来断开了链接。重命名(2)
  • open(路径名,O|u CREAT | O_EXCL,0644)
    创建并打开一个新文件。(别忘了在第三个参数中设置模式!)O_EXCL 如果路径名存在,则指示此操作失败,错误代码为EEXIST。 这是决定哪个流程应处理任务的有用方法: 成功创建文件的人。打开(2)
  • mkdir(dirname,0755)
    创建一个新目录,但如果dirname存在,将失败并返回错误代码EEXIST。这提供了目录 使用O_EXCL打开(2)的链接(2)为文件提供相同的机制。 mkdir(2)。新增2010-01-06;编辑日期2013-01-07
如您所见,
open()
只能以原子方式用于创建新的文件,而不能打开现有文件进行读取。但是,如果您想使用这种方法,可能需要使用Python的
os.open()
,它是此系统调用的代理(不要与内置的
open()
混淆)


您也可以考虑使用数据库来执行这个任务,因为它们应该提供更大的可靠性(例如,如果您的文件托管在NFS上,它根本没有实现锁定,IIRC的唯一的原子操作是<代码> MKDIR()/<代码>).< /P> < P>不,这是不可能的,这是LINU/UNIX支持的基本操作。 中的O|u create | O|u EXCL技术可以在这里工作。您不必以独占方式创建目标文件,而是以独占方式创建一个锁文件,其名称可以预期地从目标文件派生而来。例如,

os.path.join(“/tmp”,hashlib.md5(target_filename).hexdigest()+”.lock”)


但是,正如其他人所建议的,不清楚是否需要同时保护目标文件的创建及其校验和+可能的替换。
fcntl
咨询锁将满足您的需要。

对您提到的问题的回答指出,在Linux中不可能自动打开和锁定文件。的确