Python shelve.open 上的资源暂时不可用

问题描述 投票:0回答:3

我有一个执行以下操作的 Python 应用程序:

  • 由另一个进程每 2-3 分钟调用一次,以便使用
    with shelve.open(shelvefilename, flag='c')
    存储对象。
  • 被另一个/多个进程每分钟调用很多次,以便使用
    with shelve.open(shelvefilename, flag='r')
  • 读取该搁置文件

问题是有时我会收到

_gdbm.error: [Errno 11] Resource temporarily unavailable
错误:

   File "/path/to/myprog.py", line 755, in mymethod
    with shelve.open(shelvefilename, flag='r') as shlvfile:
  File "/usr/local/lib/python3.6/shelve.py", line 243, in open
    return DbfilenameShelf(filename, flag, protocol, writeback)
  File "/usr/local/lib/python3.6/shelve.py", line 227, in __init__
    Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
  File "/usr/local/lib/python3.6/dbm/__init__.py", line 94, in open
    return mod.open(file, flag, mode)
_gdbm.error: [Errno 11] Resource temporarily unavailable

我的猜测是,发生这种情况是因为在某个时刻我打开了搁置文件以进行读取和写入操作,这根据定义是“有问题的”。 有什么方法可以在不影响读取操作的情况下更新搁置文件?

python concurrency shelve
3个回答
3
投票
threading.Lock()

对象来解决该问题。


from threading import Lock import shelve mutex = Lock() mutex.acquire() db = shelve.open(db_name) # write to db db.close() mutex.release()

可以找到代码片段的原始来源和该想法的来源@ 
http://georg.io/2014/06/Python-Shelve-Thread-Safety

“threading.Lock()”对象的工作原理是阻塞其他Python线程,直到它被释放。请参阅

https://docs.python.org/2/library/threading.html#lock-objects


1
投票

想象一下您读取了文件的一部分,其中此时仅写入了某些值的一半。读取将无法正确解析该条目,也可能无法正确解析所有后续条目。换句话说,它迟早会坏掉。

我认为最好的方法是将“搁置”集中在单个进程中或使用数据库。


0
投票

使用 Shelve 时,我喜欢编写一个具有内存模型并定期同步到磁盘的包装器。这也增加了一点类型安全性。

您可以修改类型(或完全删除它),还可以更新同步以满足您的需求。

from typing import TypedDict, Dict, Optional import shelve import threading class TokenInfo(TypedDict): access_token: str expires_at: int refresh_token: str class TokenStore: def __init__(self, filename: str): self.lock = threading.Lock() self.filename = filename self.store: Dict[str, TokenInfo] = self.load_from_shelve() def load_from_shelve(self) -> Dict[str, TokenInfo]: # Load data from shelve into memory with shelve.open(self.filename) as shelf: return {key: value for key, value in shelf.items()} def get(self, key: str) -> Optional[TokenInfo]: # Return the value from the in-memory store with self.lock: return self.store.get(key) def set(self, key: str, value: TokenInfo) -> None: # Set the value in the in-memory store with self.lock: self.store[key] = value self.sync_to_shelve() def sync_to_shelve(self) -> None: # Synchronize the in-memory store with the shelve file with shelve.open(self.filename, 'c') as shelf: for key, value in self.store.items(): shelf[key] = value

然后你就可以这样使用它

# Usage example token_store = TokenStore('cache/token_store') # Set a token token_store.set('user123', {'access_token': 'abcd', 'expires_at': 1234567, 'refresh_token': 'efgh'}) # Get a token print(token_store.get('user123'))

© www.soinside.com 2019 - 2024. All rights reserved.