У меня есть модуль кэширования urllib2, что время от времени происходит сбой из-за следующий код:Расового условие создания папки в Python
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
для /tmp/example/
, который ломает, если вы используете /tmp/
в качестве директории кэша (как он пытается сделать /tmp.lock
).
Короче говоря, мне нужно кэшировать urllib2
ответы на диск. Для этого мне нужно получить доступ к известному каталогу (создав его, если требуется), безопасным способом многопроцессорности. Он должен работать на OS X, Linux и Windows.
Мысли? Единственное альтернативное решение, о котором я могу думать, - это переписать модуль кеша с использованием хранилища SQLite3, а не файлов.
Возможно! Я подумал об этом, так же, как я перечитывал вопрос, прежде чем отправлять его. Я реализовал это (http://github.com/dbr/tvdb_api/blob/468d9f816373b14ef3a483fca07e031b69fa62f9/cache.py#L103-114), и получит человека, который сообщил об ошибке, чтобы проверить его в ближайшее время. – dbr
Это, кажется, работает отлично, спасибо! – dbr
@dbr: обратите внимание, что в строке 114 вы хотите 'raise e', так как это уже экземпляр' OSError'. http://github.com/dbr/tvdb_api/blob/468d9f816373b14ef3a483fca07e031b69fa62f9/cache.py#L114 – nosklo