Race-condition creating folder in Python
我有一个URLLIB2缓存模块,由于以下代码偶尔崩溃:
1 2 | if not os.path.exists(self.cache_location): os.mkdir(self.cache_location) |
问题是,在执行第二行时,文件夹可能存在,并将出错:
1 2 3 | File".../cache.py", line 103, in __init__ os.mkdir(self.cache_location) OSError: [Errno 17] File exists: '/tmp/examplecachedir/' |
这是因为脚本同时启动了无数次,由第三方代码我无法控制。
代码(在我尝试修复bug之前)可以在Github上的此处找到
我不能使用tempfile.mkstemp,因为它使用一个随机命名的目录(这里是tempfile.py源)来解决争用条件,这会破坏缓存的目的。
我不想简单地放弃错误,因为如果文件夹名作为文件存在(不同的错误),则会引发相同的错误errno 17错误,例如:
1 2 3 4 5 6 7 8 | $ touch blah $ python >>> import os >>> os.mkdir("blah") Traceback (most recent call last): File"", line 1, in OSError: [Errno 17] File exists: 'blah' >>> |
我不能使用
所以,我试着写一个简单的基于文件的锁(这个版本可以在这里找到),但这有一个问题:它创建了一个更高级别的锁文件,所以
简而言之,我需要缓存
思想?我能想到的唯一替代解决方案是使用sqlite3存储而不是文件重写缓存模块。
而不是
1 2 | if not os.path.exists(self.cache_location): os.mkdir(self.cache_location) |
你可以做到
1 2 3 4 | try: os.makedirs(self.cache_location) except OSError: pass |
因为你最终会得到相同的功能。
免责声明:我不知道这可能是怎样的Python。
使用
如果您需要做大量的"选择"、并发插入和过滤,那么使用
重读你的问题(和评论),我能更好地理解你的问题。
文件可以创建相同的竞争条件的可能性是什么?
如果它足够小,那么我会做如下的事情:
1 2 3 4 5 | if not os.path.isfile(self.cache_location): try: os.makedirs(self.cache_location) except OSError: pass |
而且,读你的代码,我会改变
1 2 3 4 | else: # Our target dir is already a file, or different error, # relay the error! raise OSError(e) |
到
1 2 3 4 | else: # Our target dir is already a file, or different error, # relay the error! raise |
因为它确实是您想要的,所以python要重新发出完全相同的异常(just nitpicking)。
还有一件事,可能这对您有用(仅限于Unix)。
我最后得到的代码是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import os import errno folder_location ="/tmp/example_dir" try: os.mkdir(folder_location) except OSError as e: if e.errno == errno.EEXIST and os.path.isdir(folder_location): # File exists, and it's a directory, # another process beat us to creating this dir, that's OK. pass else: # Our target dir exists as a file, or different error, # reraise the error! raise |
当你有比赛条件时,EAFP(比许可更容易请求宽恕)比LBYL(跳跃前先看)更有效。
错误检查策略
您能否捕获异常,然后测试该文件是否作为目录存在?