我的 11.3MB 数据库文件用 Pickle 加载需要 3 分钟

My 11.3MB database file takes 3 minutes to load with Pickle

我有大量 database/dictionary 随机用户对电影的评分,总计约 400,000 项。我使用 pickle 将其存储在同一目录中的 .p 文件中。在我的 Enthought Canopy IDE 中按下 运行 按钮时,加载 11.3MB 的文件需要 3 分钟多的时间,假设 1GB 的视频可以在几秒钟内加载并启动。

这是在 2TB 7200RPM 硬盘上。在 Samsung 850 EVO SSD 上,它需要大约相同或更长的时间。是什么原因造成的?我的IDE?泡菜? 我有 Python 2.7.

我正在用它来阅读:

import cPickle as pickle
ratings = pickle.load( open( ratings_database_file, "rb" ) )

播放大型视频文件通常不会一次将整个文件读入内存 - 媒体播放器会缓冲足够的时间来开始显示它,然后根据需要流式传输更多内容。如果你想让你的数据库更快速,你可以用不同的方式存储它,这样它就不需要把所有的东西都加载到内存中开始——就像一个小得多的索引,就像一棵树,在数据记录中有偏移量。

也就是说,3 分钟听起来很极端。有些事情你可以尝试让它更快:

  • 如果您使用 Python 2,请使用 cPickle,正如评论所建议的那样(Python 3 会自动执行此操作)。
  • 确保您使用的是最新的二进制 pickle 格式。
  • Profile the loading - unpickling objects can call methods on the objects as it loads them (depending on the classes) and it might be that they're doing work you're not expecting. I've found snakevis or RunSnakeRun 对于探索探查器输出很有用。
  • 探索这一点的另一种方法是更改​​您正在存储的对象的格式 - 将其腌制为元组列表,或者甚至将其写成(gzipped)JSON.

如果您不需要在内存中同时存储整个评级字典,您可能会考虑将字典存储到数据库中,或者由一组文件组成的 'on-disk' 数据库。我是 klepto 的作者,它非常适合这个目的——它为 SQL 数据库或磁盘上的文件目录提供了一个 python 字典抽象接口;两者看起来都符合您的目的。

简而言之,您可以直接与数据库交互 (cached=False),也可以通过内存中的字典进行缓冲 (cached=True)。

要建立存档:

>>> import klepto
>>> d = klepto.archives.dir_archive('ratings', serialized=True)
>>> d['Dune'] = 10
>>> d['Monty Python'] = 9
>>> d['Avengers'] = 2
>>> d.dump()

要阅读条目或存档:

>>> import klepto
>>> d = klepto.archives.dir_archive('ratings', serialized=True)
>>> d.load('Dune')
>>> d
dir_archive('ratings', {'Dune': 10}, cached=True)
>>> d['Dune']
10
>>> d.load()
>>> d.keys()
['Monty Python', 'Avengers', 'Dune']
>>> d.items()
[('Monty Python', 9), ('Avengers', 2), ('Dune', 10)]
>>> 

如果您不需要所有条目,加载速度应该会快得多。第二个好处是您可以非常轻松地尝试不同的编码和存储格式,看看哪种最适合您的需要。