python - Python 中的竞争条件创建文件夹

标签 python caching race-condition

我有一个 urllib2 缓存模块,它偶尔会因为以下代码而崩溃:

if not os.path.exists(self.cache_location):
    os.mkdir(self.cache_location)

问题是,第二行执行的时候,文件夹可能已经存在,会报错:

  File ".../cache.py", line 103, in __init__
    os.mkdir(self.cache_location)
OSError: [Errno 17] File exists: '/tmp/examplecachedir/'

这是因为脚本被我无法控制的第三方代码同时启动了很多次。

可以找到代码(在我尝试修复错误之前)here, on github

我无法使用 tempfile.mkstemp ,因为它通过使用随机命名的目录 ( tempfile.py source here ) 来解决竞争条件,这将破坏缓存的目的。

我不想简单地丢弃错误,因为如果文件夹名称作为文件存在(不同的错误),则会引发相同的错误 Errno 17 错误,例如:

$ touch blah
$ python
>>> import os
>>> os.mkdir("blah")
Traceback (most recent call last):
  File "", line 1, in 
OSError: [Errno 17] File exists: 'blah'
>>>

我无法使用 threading.RLock,因为代码是从多个进程调用的。

因此,我尝试编写一个简单的基于文件的锁(that version can be found here),但这有一个问题:它创建了上一层的锁文件,所以 /tmp/example.lock for /tmp/example/,如果您使用 /tmp/ 作为缓存目录(因为它试图制作 /tmp.lock),它会中断。 .

简而言之,我需要将 urllib2 响应缓存到磁盘。为此,我需要以多进程安全方式访问已知目录(如果需要,创建它)。它需要在 OS X、Linux 和 Windows 上运行。

想法?我能想到的唯一替代解决方案是使用 SQLite3 存储而不是文件重写缓存模块。

最佳答案

代替

if not os.path.exists(self.cache_location):
    os.mkdir(self.cache_location)

你可以做

try:
    os.makedirs(self.cache_location)
except OSError:
    pass

因为您最终会得到相同的功能

免责声明:我不知道这可能有多 Pythonic。


使用 SQLite3可能有点矫枉过正,但会为您的用例增加很多功能和灵 active 。 p>

如果你必须做大量的“选择”、并发插入和过滤,那么使用 SQLite3 是个好主意,因为它不会比简单的文件增加太多复杂性(这可能是有争议的它消除了复杂性)。


重读你的问题(和评论)我可以更好地理解你的问题。

文件产生相同竞争条件的可能性有多大?

如果它足够小,那么我会做类似的事情:

if not os.path.isfile(self.cache_location):
    try:
        os.makedirs(self.cache_location)
    except OSError:
        pass

另外,阅读你的代码,我会改变

else:
    # Our target dir is already a file, or different error,
    # relay the error!
    raise OSError(e)

else:
    # Our target dir is already a file, or different error,
    # relay the error!
    raise

因为这确实是您想要的,Python 重新引发完全相同的异常(只是吹毛求疵)


还有一件事,可能是this可能对你有用(仅限类 Unix)。

关于python - Python 中的竞争条件创建文件夹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1586648/

相关文章:

ios - 缓存整个网站 - Swift

python - kNN - 如何根据计算的距离在训练矩阵中定位最近的邻居

python - 更改函数以返回整列

python - 从具有匹配词的主列表生成列表,无论顺序如何

javascript - render 没有被一个 api 调用,而是被另一个 api 调用

ruby-on-rails - Ruby on Rails 中的竞争条件

c++ - 全局变量多读一写多线程安全吗?

python - 如何在 Heroku 上安排 python 脚本

ajax - 使 Internet Explorer 中的 bfcache 像 Firefox 一样工作

asp.net-mvc - 如何将SQL表数据导入Redis缓存?