I tiene un módulo urllib2 almacenamiento en caché, que esporádicamente se bloquea por lo siguiente código:Race-condición creación de carpeta en Python
if not os.path.exists(self.cache_location):
os.mkdir(self.cache_location)
El problema es que en el momento está siendo ejecutada la segunda línea, la carpeta puede existir, y se error:
File ".../cache.py", line 103, in __init__ os.mkdir(self.cache_location) OSError: [Errno 17] File exists: '/tmp/examplecachedir/'
Esto es porque el guión está lanzado simultáneamente en numerosas ocasiones, por el código de terceros no tengo ningún control sobre.
El código (antes he tratado de corregir el error) se puede encontrar here, on github
no puedo usar el tempfile.mkstemp, como los que resuelve la condición de carrera mediante el uso de un directorio de nombre aleatorio (tempfile.py source here), lo que arruinaría el propósito de la memoria caché
no quiero por desechar el error, ya que el mismo error se eleva Errno 17 de error si el nombre de la carpeta existe como un archivo (un error diferente), por ejemplo:
$ touch blah $ python >>> import os >>> os.mkdir("blah") Traceback (most recent call last): File "", line 1, in OSError: [Errno 17] File exists: 'blah' >>>
no puedo utilizando threading.RLock
ya que el código se llama desde múltiples procesos.
tanto, he intentado escribir un bloqueo basado en archivos simples (that version can be found here), pero esto tiene un problema: se crea el fichero de bloqueo en un nivel superior, por lo /tmp/example.lock
para /tmp/example/
, que se rompe si se utiliza /tmp/
como un directorio caché (como se intenta hacer /tmp.lock
) ..
En resumen, necesito almacenar en caché urllib2
respuestas al disco. Para hacer esto, necesito acceder a un directorio conocido (crearlo, si es necesario), de una manera segura en multiprocesos. Debe funcionar en OS X, Linux y Windows.
¿Pensamientos? La única solución alternativa que puedo pensar es volver a escribir el módulo de caché utilizando SQLite3 storage, en lugar de archivos.
¡Posiblemente! Pensé en eso justo cuando estaba volviendo a leer la pregunta, antes de enviarla ... Lo he implementado (http://github.com/dbr/tvdb_api/blob/468d9f816373b14ef3a483fca07e031b69fa62f9/cache.py#L103-114), y hará que la persona que informó el error lo pruebe en breve. – dbr
Esto parece funcionar perfectamente, gracias! – dbr
@dbr: tenga en cuenta que en la línea 114, quiere 'raise e' ya que ya es una instancia de' OSError'. http://github.com/dbr/tvdb_api/blob/468d9f816373b14ef3a483fca07e031b69fa62f9/cache.py#L114 – nosklo