【问题标题】:How to avoid a race condition with makedirs?如何避免与 makedirs 的竞争条件?
【发布时间】:2014-02-02 22:41:41
【问题描述】:

我正在尝试将以下伪代码转换为 Python:

如果  不存在:
    为  创建所有子目录
在 
中创建一个文件

这听起来很简单,可以使用 os.makedirsos.path.isdir 完成:

if not os.path.isdir('/some/path'):
    os.makedirs('/some/path')
open('/some/path/test.txt', 'w')

但是,经过进一步检查,显然存在竞争条件。考虑以下时间表:

  1. 指定的目录(/some/path)不存在
  2. Python 解释器执行第一行,计算结果为True
  3. 另一个进程创建目录 (/some/path)
  4. makedirs 引发 OSError 异常,因为该目录已存在

如果目录最初存在但在执行最后一行之前被另一个进程删除,也会出现问题。

谈到 Python,“请求宽恕比请求许可更容易。”考虑到这一点,上面的片段可以写得更好:

try:
    os.makedirs('/some/path')
except OSError:
    pass
open('/some/path/test.txt', 'w')

这解决了上述两个问题,但产生了第三个问题:os.makedirs 在以下情况之一发生时引发OSError 异常:

  • 目录已经存在
  • 无法创建目录

这意味着无法确定这两个条件中的哪一个导致引发异常。换句话说,实际的失败将被默默地忽略,这不是我想要的。

我该如何解决这个问题?

【问题讨论】:

    标签: python directory race-condition


    【解决方案1】:

    我会注意到,所有这些在 python 3 中都更加理智; FileExistsErrorPermissionError 是您可以捕获的单独的(OSError 的子类)异常,os.makedirs 甚至有一个 exist_ok kwarg 来抑制前者,当您对已经存在的目录感到满意时。

    如果您想检查OSError 的原因,该信息位于e.args 的元组中(或者如果您只想查看错误代码,则可以选择e.errno):

    try:
        os.makedirs('/etc/python')
    except OSError as e:
        print e.args
    
    (17, 'File exists')
    
    try:
        os.makedirs('/etc/stuff')
    except OSError as e:
        print e.args
    
    (13, 'Permission denied')
    
    try:
        os.makedirs('/etc/stuff')
    except OSError as e:
        print e.errno
    
    13
    

    因此,您必须进行一些自省,并在 except 块中以不同方式处理两个错误代码。

    【讨论】:

    • 好主意!我可以使用errno.EEXIST 而不是硬编码17
    猜你喜欢
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 2010-09-25
    • 2016-09-20
    • 1970-01-01
    相关资源
    最近更新 更多