2009-01-28 159 views

回答

7

擱置模塊使用底層數據庫包(如dbm,gdbm或bsddb)。

restrictions pragraph說(我的重點):

的貨架模塊不支持並行讀/寫訪問擱置對象。 (多個同時讀取訪問是安全的。)當一個程序有一個可寫入的架子時,其他程序不應該打開它來讀取或寫入。 Unix文件鎖定可以用來解決這個問題,但是這在Unix版本中是不同的,並且需要關於所使用的數據庫實現的知識。

結論:它取決於操作系統和底層數據庫。爲了保持可移植性,不要建立在併發上。

2

根據最佳答案,擱置多位作者並不安全。我使貨架更安全的方法是編寫一個封裝,用於打開和訪問貨架元素。包裝代碼看起來是這樣的:有興趣的

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

我實現Ivo's approach爲上下文管理器,任何人:

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

順便說一句我認爲限制比較並交換特定頂級的但我不確定更新密鑰是否可能不會覆蓋所有其他密鑰,也可能依賴於底層數據庫,因此更好地鎖定整個事情並保證安全 – 2011-11-15 17:48:00