shelve
模块的文档在限制下提出以下声明:
搁置模块不支持对搁置对象的并发读/写访问。 (多个同时读取访问是安全的。)
据我所知,这意味着只要我不尝试让多个进程同时写入一个架子,我就应该清楚了。使用相同磁盘架作为只读缓存的多个进程应该是安全的。正确?
显然不是。经过一番挣扎之后,我最终得到了一个测试用例,当从架子上异步读取时,它似乎表现出一些非常糟糕的行为。以下脚本:
Shelf
并使用"i" : 2*i
填充i
从1到10。Spawns进程从shelf文件中检索每个键的值,并报告是否检索了值。
import multiprocessing
import shelve
SHELF_FILE = 'test.shlf'
def store(key, obj):
db = shelve.open(SHELF_FILE, 'w')
db[key] = obj
db.close()
def load(key):
try:
db = shelve.open(SHELF_FILE, 'r')
n = db.get(key)
if n is not None:
print('Got result {} for key {}'.format(n, key))
else:
print('NO RESULT for key {}'.format(key))
except Exception as e:
print('ERROR on key {}: {}'.format(key, e))
finally:
db.close()
if __name__ == '__main__':
db = shelve.open(SHELF_FILE, 'n') # Create brand-new shelf
db.close()
for i in range(1, 11): # populate the new shelf with keys from 1 to 10
store(str(i), i*2)
db = shelve.open(SHELF_FILE, 'r') # Make sure everything got in there.
print(', '.join(key for key in db)) # Should print 1-10 in some order
db.close()
# read each key's value from the shelf, asynchronously
pool = multiprocessing.Pool()
for i in range(1, 11):
pool.apply_async(load, [str(i)])
pool.close()
pool.join()
此处的预期输出自然为2, 4, 6, 8
,最多为20(按某种顺序)。相反,无法从架子中检索任意值,有时请求会导致shelve
完全爆炸。实际输出如下所示:(" NO RESULT"行表示返回None
的键:)
6, 7, 4, 5, 2, 3, 1, 10, 8, 9
ERROR on key 3: need 'c' or 'n' flag to open new db
ERROR on key 6: need 'c' or 'n' flag to open new db
Got result 14 for key 7
NO RESULT for key 10
Got result 2 for key 1
Got result 4 for key 2
NO RESULT for key 8
NO RESULT for key 4
NO RESULT for key 5
NO RESULT for key 9
根据错误消息,我的直觉是外部资源(可能是.dir
文件?)没有被正确刷新到磁盘(或者可能被其他进程删除了? )。即使这样,我也期待一个进程等待磁盘资源的速度减慢,而不是这些"哦,我猜它不存在"或者"你在说什么,甚至不是货架文件"结果。坦率地说,无论如何我都不希望有任何文件写入,因为工作进程只使用只读连接......
我有什么遗漏,或shelve
在多处理环境中完全无法使用吗?
这是Windows 7上的Python 3.3 x64,如果结果证明是相关的。
答案 0 :(得分:1)
shelve.open()
文档中有警告评论:
打开一个持久字典。指定的文件名是基础 底层数据库的文件名。作为副作用,是一种延伸 可以添加到文件名中,可以创建多个文件。
尝试将预先打开的搁置(而不是文件名)传递给池线程,并查看行为是否发生了变化。也就是说,我没有2.7,Win7-64的副本(输出当然搞砸了)。