允许在Python、pypar和mpich2中序列化一个shelve对象

1 投票
2 回答
884 浏览
提问于 2025-04-16 13:29

我有一些老旧的Python代码,它使用pypar和mpich2在多个节点之间传输数据。由于某种原因,数据存储在shelve中,而pypar想要把shelve中的数据进行序列化(也就是“打包”)后发送到其他节点。但shelve的数据不能被打包。所以我想把shelve中的数据转换成可以通过pypar发送的格式,这样在发送之前就能进行打包。有没有什么建议?我可以把shelve转换成json格式,然后再打包吗?

2 个回答

1

有个建议是把你的shelve对象转换成字典,这个方法是可行的。

不过(这可能有点不太靠谱,但)考虑到你的数据已经存储在数据库文件里,或许可以试试让其他节点直接从这个shelve文件中加载数据,而不是通过MPI发送数据。我假设所有节点都能访问同一个文件系统,因为你是用MPI来运行它们的。

老实说,我觉得MPI发送的速度应该更快,特别是在共享内存的系统上,因为很多MPI的实现会退回到内存复制。不过,一旦你考虑到重新打包和解包数据的额外开销,速度差距可能就不大了!

我猜这主要取决于你运行的节点数量和你的通信方式。

1

试着把shelve转换成一个 dict(),然后再进行序列化:

sdb = shelve.open('foo.db')
sdb['abc'] = {'a': 1, 'b': 2}
tmp = cPickle.dumps(dict(sdb), 2)
print cPickle.loads(tmp)
{'abc': {'a': 1, 'b': 2}}

更新: (对评论中问题的回应):一个 dict 可以从任何映射对象中复制键值对,所以如果那个对象实现了 keys__getitem__ 这两个方法,它就能工作。因为shelve是一个映射对象,所以 dict 的复制构造函数可以从shelve中读取键值对,然后你可以把得到的dict进行序列化,发送到其他主机。

下面的例子展示了 dict 复制一个对象所需的最基本接口:

class Foo(object):

    def __init__(self):
        self.value = 0

    def keys(self):
        return ['a', 'b']

    def __getitem__(self, key):
        v = self.value
        self.value += 1
        return self.value

foo = Foo()
print dict(foo)
print dict(foo)

输出

{'a': 1, 'b': 2}
{'a': 3, 'b': 4}

更新: 如果想把一个dict的内容重新添加到shelve中,可以使用 update()

d = {'a': 1, 'b': 2}
s = shelve.open('foo.db')
s.update(d)
print s
{'a': 1, 'b': 2}

撰写回答