在Python中保存和加载大型字典的最快方法

29

我有一个相对较大的字典。如何知道它的大小?嗯,当我使用cPickle保存它时,文件的大小将增长约400Mb。cPickle应该比pickle快得多,但是加载和保存这个文件需要很长时间。我在一台配备2.6 GHz双核处理器、4GB内存的Linux机器上工作。有没有人有更快的建议来在Python中保存和加载字典?谢谢。


你的字典中有哪些键和值?Python数据类型是否任意? - Sven Marnach
能否使用SQLite代替,这样就不必将整个东西加载到内存中了? - Marco
将 cPickle 的 protocol 参数设置为 2。 - Andrew
@Sven:键是由2到5个成员不等的元组。这些成员是以UTF-8编码的字符串。 - Hossein
6个回答

24

使用cPickle的 protocol=2选项。默认协议(0)速度较慢,且在磁盘上产生更大的文件。

如果您只想使用比内存容量更大的字典,则shelve模块是一种快速而简单的解决方案。它类似于内存中的字典,但将自身存储在磁盘而不是内存中。 shelve基于cPickle,因此请务必将协议设置为非0。

与cPickle相比,sqlite等数据库的优点取决于您的用例。您有多频繁地写入数据?您预计读取每个数据的次数有多少次?您是否希望对写入的数据执行搜索,或者逐个加载这些数据?

如果您只进行一次写入和多次读取,并且一次加载一个数据,则一定要使用数据库。如果您只进行一次写入和一次读取,则使用cPickle(使用除默认协议=0之外的任何协议)将难以超越。如果只是需要一个大的持久化字典,请使用shelve。


3
我有同样的问题。我的字典超过了16GB。为什么shelve是一个“脏”解决方案? - tommy.carstensen
@tommy.carstensen 看一下 - Steven J Owens
1
@tommy.carstensen 请查看此链接 https://dev59.com/82435IYBdhLWcg3wuimz#58051642 ,其中解释了shelve不是非常容错的。如果您在更新shelve时未能关闭它,或者发生中断事件,它很容易损坏。 - Steven J Owens

20

我知道这是一个老问题,但对于那些仍在寻找答案的人来说,作为此问题的更新: protocol参数已在Python 3中进行了更新,现在甚至有更快,更高效的选项(即protocol=3protocol=4),可能在Python 2下无法使用。 您可以在参考文献中了解更多信息。

为了始终使用您正在使用的Python版本支持的最佳协议,您可以简单地使用pickle.HIGHEST_PROTOCOL。以下示例摘自参考文献

import pickle
# ...
with open('data.pickle', 'wb') as f:
    # Pickle the 'data' dictionary using the highest protocol available.
    pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

2
我尝试过很多项目,得出结论:在保存数据方面,shelvepickle更快。两者在加载数据方面的表现相同。 实际上,shelve是一个不太完美的解决方案。这是因为你必须非常小心。如果你在打开shelve文件后没有关闭它,或者由于任何原因导致你的代码在打开和关闭之间发生中断,shelve文件有很大的可能性会损坏(导致令人沮丧的KeyErrors);这真的很烦人,因为我们使用它们是因为要存储我们的大型字典文件,而这些文件显然也需要很长时间来构建。 这就是为什么shelve是一个不太完美的解决方案...尽管如此,它还是更快的。所以!

2

Sqlite

将数据存储在Sqlite数据库中可能是值得的。虽然重构程序以使其与Sqlite一起工作会带来一些开发开销,但查询数据库变得更加容易和高效。

此外,您还可以免费获得事务、原子性、序列化、压缩等功能。

根据您使用的Python版本,您可能已经内置了sqlite。


1
你可以试着压缩你的字典(有一些限制,详见 this post),如果磁盘访问是瓶颈的话,这种方式会更有效。

0

这是大量的数据... 你的字典包含哪些内容?如果只有原始或固定的数据类型,也许真正的数据库或自定义文件格式是更好的选择?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接