python - 搁置只读多处理不安全吗?

标签 python persistence multiprocessing shelve

shelve 模块的文档根据限制 做出以下声明:

The shelve module does not support concurrent read/write access to shelved objects. (Multiple simultaneous read accesses are safe.)

据我所知,这意味着只要我不尝试让多个进程同时写入一个 shelf,我应该是安全的。使用同一个架子作为只读缓存的多个进程应该是安全的。对吧?

显然不是。经过一番努力,我最终得到了一个测试用例,该用例似乎在从货架上异步读取时展示了一些非常糟糕的行为。以下脚本:

  1. 创建一个 Shelf 并用 "i": 2*i 填充 i 从 1 到 10。
  2. 读回所有这些值,以确保它们被正确存储。
  3. 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,如果相关的话。

最佳答案

shelve.open() 文档中有警告注释:

Open a persistent dictionary. The filename specified is the base filename for the underlying database. As a side-effect, an extension may be added to the filename and more than one file may be created.

尝试将预先打开的搁置(而不是文件名)传递给池线程,并查看行为是否发生变化。就是说,我没有 2.7、Win7-64 的重现(输出当然是一团糟)。

关于python - 搁置只读多处理不安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23397979/

相关文章:

python - 涉及 Python float(sys.argv[1]) 的未知代码错误

python - Python 中的 MinHeap/MaxHeap 实现

java - Clojure 相当于 Python 的 lxml 库?

php - 使用 popen 执行多处理脚本时输出困惑

python - multiprocessing.dummy 为什么 AttributeError : 'module' object has no attribute 'dummy'

Python 多进程池。当其中一个工作进程确定不需要完成更多工作时如何退出脚本?

python - 当生成的线程在 python 中死亡时如何终止调用进程?

java - 集合中的新实体不会被持久化

mysql - JDBCExceptionReporter [错误] 字段 'id' 没有默认值

java - 如何配置 persistence.xml 提供者标签