2009-01-28 6 views

Antwort

7

Das Shelve-Modul verwendet ein zugrunde liegendes Datenbankpaket (z. B. dbm, gdbm oder bsddb).

Die restrictions pragraph sagt (Hervorhebung von mir):

Das shelve Modul nicht gleichzeitiges Lesen nicht unterstützt/Schreibzugriff auf Eis gelegt Objekte. (Mehrere gleichzeitige Lesezugriffe sind sicher.) Wenn ein Programm zum Schreiben geöffnet ist, sollte es kein anderes Programm zum Lesen oder Schreiben öffnen. Die Unix-Dateisperrung kann verwendet werden, um dies zu lösen, aber dies unterscheidet sich zwischen Unix-Versionen und erfordert Kenntnisse über die verwendete Datenbankimplementierung.

Fazit: Es hängt von OS und der zugrunde liegenden DB ab. Um die Dinge portabel zu halten, sollten Sie nicht auf Parallelität aufbauen.

2

Laut der Top-Antwort ist es nicht sicher, mehrere Autoren zum Regal zu haben. Mein Ansatz, um Regale sicherer zu machen, besteht darin, eine Verpackung zu schreiben, die sich um das Öffnen und den Zugriff auf Regalelemente kümmert. Der Wrapper-Code sieht ungefähr so ​​aus:

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() 
2

I Ivo's approach als Kontext-Manager implementiert haben, für alle Interessierten:

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 
+0

btw dachte ich die Vergleichs- und Swap auf bestimmte top- der Beschränkung Level-Schlüssel, aber ich bin mir nicht sicher, ob das Aktualisieren eines Schlüssels nicht alle anderen überschreiben kann, und es kann auch von der zugrunde liegenden DB abhängen, also besser die ganze Sache sperren und sicher sein –