7

Python shelve モジュールには、2 つのプロセスが同時にファイルに書き込んでいないことを確認するための保護が組み込まれていますか?

4

3 に答える 3

8

shelve モジュールは、基礎となるデータベース パッケージ (dbm、gdbm、bsddb など) を使用します。

制限の段落には次のように書かれています(私の強調):

shelve モジュールは、保留オブジェクトへの同時読み取り/書き込みアクセスをサポートしていません。(複数の同時読み取りアクセスは安全です。) プログラムが書き込み用に開いているシェルフを持っている場合、他のプログラムはそれを読み取りまたは書き込み用に開いてはいけません。Unix ファイル ロックを使用してこれを解決できますが、これは Unix バージョンによって異なり、使用するデータベースの実装に関する知識が必要です。

結論: OS と基礎となる DB に依存します。移植性を維持するために、並行性に基づいて構築しないでください。

于 2009-01-28T06:38:26.510 に答える
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()
于 2011-10-27T11:31:56.997 に答える
2

興味のある人のために、コンテキストマネージャーとして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
于 2011-11-15T15:42:54.513 に答える