Python модуль полки вопрос - PullRequest
6 голосов
/ 28 января 2009

Имеется ли в модуле полки Python какая-либо защита, обеспечивающая одновременную запись двух файлов в файл?

Ответы [ 3 ]

7 голосов
/ 28 января 2009

Модуль shelve использует базовый пакет базы данных (например, dbm, gdbm или bsddb).

Ограничения ПРАКТ говорит (мой акцент):

Модуль полки не поддерживает одновременный доступ для чтения / записи к отложенным объектам . (Несколько одновременных обращений к чтению безопасны.) Если в программе открыта полка для записи, никакая другая программа не должна открывать ее для чтения или записи. Для решения этой проблемы можно использовать блокировку файлов Unix, но она отличается в разных версиях Unix и требует знаний об используемой реализации базы данных.

Вывод: это зависит от ОС и базовой БД. Чтобы сохранить переносимость, не опирайтесь на параллелизм.

2 голосов
/ 15 ноября 2011

Я реализовал подход Ivo как менеджер контекста, для всех, кто заинтересован:

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
2 голосов
/ 27 октября 2011

Согласно верхнему ответу, небезопасно иметь несколько писателей на полке. Мой подход к тому, чтобы сделать полки более безопасными, - написать оболочку, которая заботится об открытии и доступе к элементам полки. Код оболочки выглядит примерно так:

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