Question

Le module de rangement Python est-il doté d'une protection intégrée garantissant que deux processus n'écrivent pas dans un fichier en même temps?

Était-ce utile?

La solution

Le module shelve utilise un package de base de données sous-jacent (tel que dbm, gdbm ou bsddb).

Le restrictions du paragraphe dit (mon emphase):

  

Le module shelve ne prend pas en charge les accès en lecture / écriture simultanés aux objets stockés . (Plusieurs accès en lecture simultanée sont sécurisés.) Lorsqu'un programme a une étagère ouverte en écriture, aucun autre programme ne doit l'avoir ouverte en lecture ou en écriture. Le verrouillage de fichier Unix peut être utilisé pour résoudre ce problème, mais cela diffère d’une version Unix à l’autre et nécessite des informations sur la mise en oeuvre de la base de données utilisée.

Conclusion: cela dépend du système d’exploitation et du DB sous-jacent. Pour garder les choses portables, ne construisez pas sur la concurrence.

Autres conseils

Comme indiqué dans la réponse précédente, il n’est pas prudent d’avoir plusieurs rédacteurs sur le plateau. Mon approche pour rendre les étagères plus sûres consiste à écrire une enveloppe qui s’occupe d’ouvrir et d’accéder aux éléments des étagères. Le code enveloppe ressemble à ceci:

def open(self, mode=READONLY):
    if mode is READWRITE:
        lockfilemode = "a" 
        lockmode = LOCK_EX
        shelve_mode = 'c'
    else:
        lockfilemode = "r"
        lockmode = LOCK_SH
        shelve_mode = 'r'
    self.lockfd = open(shelvefile+".lck", lockfilemode)
    fcntl.flock(self.lockfd.fileno(), lockmode | LOCK_NB)
    self.shelve = shelve.open(shelvefile, flag=shelve_mode, protocol=pickle.HIGHEST_PROTOCOL))
def close(self):
    self.shelve.close()
    fcntl.flock(self.lockfd.fileno(), LOCK_UN)
    lockfd.close()

J'ai implémenté la approche d'Ivo en tant que gestionnaire de contexte, pour tous intéressé:

from contextlib import contextmanager, closing
from fcntl import flock, LOCK_SH, LOCK_EX, LOCK_UN
import shelve

@contextmanager
def locking(lock_path, lock_mode):
    with open(lock_path, 'w') as lock:
        flock(lock.fileno(), lock_mode) # block until lock is acquired
        try:
            yield
        finally:
            flock(lock.fileno(), LOCK_UN) # release

class DBManager(object):
    def __init__(self, db_path):
        self.db_path = db_path

    def read(self):
        with locking("%s.lock" % self.db_path, LOCK_SH):
            with closing(shelve.open(self.db_path, "c", 2)) as db:
                return dict(db)

    def cas(self, old_db, new_db):
        with locking("%s.lock" % self.db_path, LOCK_EX):
            with closing(shelve.open(self.db_path, "c", 2)) as db:
                if old_db != dict(db):
                    return False
                db.clear()
                db.update(new_db)
                return True
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top