我有一个执行以下操作的 Python 应用程序:
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
我的猜测是,发生这种情况是因为在某个时刻我打开了搁置文件以进行读取和写入操作,这根据定义是“有问题的”。 有什么方法可以在不影响读取操作的情况下更新搁置文件?
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-Safetyhttps://docs.python.org/2/library/threading.html#lock-objects
想象一下您读取了文件的一部分,其中此时仅写入了某些值的一半。读取将无法正确解析该条目,也可能无法正确解析所有后续条目。换句话说,它迟早会坏掉。
我认为最好的方法是将“搁置”集中在单个进程中或使用数据库。
使用 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'))