【问题标题】:os.makedir race condition in single thread? How to ensure directory created before continue单线程中的 os.mkdir 竞争条件?如何确保在继续之前创建目录
【发布时间】:2020-04-23 18:02:48
【问题描述】:

我在烧瓶应用程序中 os.makedir 的行为非常奇怪。

我有一个用于上传图片的 API 端点。每个图像应根据条件分组到目录中。如果目录不存在,则应创建目录。

最初,我的应用中有这段代码:

    # create needed dir if doesn't exist
    if not os.path.isdir(os.path.dirname(abs_path)):
        os.mkdir(os.path.dirname(abs_path))

    # create a file and save it into a needed place
    with open(abs_path, 'wb') as f:
        shutil.copyfileobj(fp, f)
        f.flush()

在 90% 的情况下,它的效果都很好。但是当请求中有两个文件时,应该放在同一个目录中,并且该目录尚未创建,我得到了这个:

flask_1  |   File "/app/storage.py", line 101, in save_file
flask_1  |     os.mkdir(os.path.dirname(abs_path))
flask_1  | FileExistsError: [Errno 17] File exists: '/static/df273d04909e71beb8b63b4d1b1c0a969ee6fc15'

它可以在 1 线程的烧瓶调试模式下以 100% 的成功率在本地复制。似乎是某种 Linux/docker 或某种缓存竞争条件。

然后我将代码简单地更改为这个:

if not os.path.isdir(os.path.dirname(abs_path)):
    try:
        os.mkdir(os.path.dirname(abs_path))
    except FileExistsError:
        # Another thread was already created the directory when
        # several simultaneous requests has come
        if os.path.isdir(os.path.dirname(abs_path)):
            pass
        else:
            raise

    # create a file and save it into a needed place
    with open(abs_path, 'wb') as f:
        shutil.copyfileobj(fp, f)
        f.flush()

问题就解决了。

但我担心在生产中使用此代码,因为同样的检查产生不同的结果是很奇怪的。

在继续第一次请求处理之前,如何确保目录确实创建了?

附:文件已就位,第二个代码 sn-p 两个文件均已就位。第一个只有目录中的第一个文件,第二个错误。

I.E.使用第一个代码 sn -p Flask 认为一切正常并继续

【问题讨论】:

  • 你确定进程是单线程运行的?

标签: python python-3.x flask operating-system race-condition


【解决方案1】:

os.makedirs 接受一个参数exist_ok,当是True 时,如果目录存在则不会引发错误

os.makedirs(os.path.dirname(abs_path), exist_ok=True)

【讨论】:

  • 是的,我知道这个选项。但我和我的团队负责人主要想了解内部流程,而不仅仅是处理错误。
猜你喜欢
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 2016-10-12
  • 2021-06-04
相关资源
最近更新 更多