对于只读多处理,搁置是不安全的吗?

时间:2014-04-30 21:04:16

标签: python persistence multiprocessing shelve

shelve模块的文档在限制下提出以下声明:

  

搁置模块不支持对搁置对象的并发读/写访问。 (多个同时读取访问是安全的。)

据我所知,这意味着只要我不尝试让多个进程同时写入一个架子,我就应该清楚了。使用相同磁盘架作为只读缓存的多个进程应该是安全的。正确?

显然不是。经过一番挣扎之后,我最终得到了一个测试用例,当从架子上异步读取时,它似乎表现出一些非常糟糕的行为。以下脚本:

  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()
    
  4. 此处的预期输出自然为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,如果结果证明是相关的。

1 个答案:

答案 0 :(得分:1)

shelve.open()文档中有警告评论:

  

打开一个持久字典。指定的文件名是基础   底层数据库的文件名。作为副作用,是一种延伸   可以添加到文件名中,可以创建多个文件。

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