【问题标题】:Python: storing big data structuresPython:存储大数据结构
【发布时间】:2014-08-24 11:02:52
【问题描述】:

我目前正在 python 中做一个项目,该项目使用相对较大的字典(大约 800 MB)。我尝试使用 pickle 存储其中一个字典,但出现 MemoryError。

在 python 中保存此类文件的正确方法是什么?我应该使用数据库吗?

【问题讨论】:

  • 这取决于您在这些字典中存储的内容。也许json module 是您可以轻松尝试的替代方法(import json; json.dumps(mydict) 看看您是否遇到相同的错误)。
  • 只需将数据转储到 csv 文件中。我已经成功地为 3GB 的文件做到了这一点
  • 您是说您的字典值字段分别为 800-MB 还是所有值的总和为 800-MB?
  • user590028 - 我的意思是整个结构,所有值的总和,是 800 MB。
  • Tim Pietzcker - 我喜欢这个想法,但我认为它行不通,因为这些值包含一系列frozensets。

标签: python data-structures pickle


【解决方案1】:

Python 标准的shelve 模块为持久对象提供了类似字典的接口。它适用于许多数据库后端,并且不受 RAM 的限制。与直接使用数据库相比,使用shelve 的优势在于您现有的大部分代码都保持原样。这是以速度为代价的(与内存中的字典相比)和灵活性的代价(与直接使用数据库相比)。

【讨论】:

  • 我使用了 shelve,因为它只需要很少的代码修改。谢谢。
【解决方案2】:

shelf 不同,klepto 不需要将整个字典存储在单个文件中(当您只需要一个条目时,使用单个文件进行读写非常慢)。此外,与shelf 不同,klepto 可以存储几乎任何类型的 Python 对象,您可以将其放入字典中(您可以存储函数、lambda、类实例、套接字、多处理队列等)。

klepto 为写入数据库提供字典抽象,包括将文件系统视为数据库(即将整个字典写入单个文件,或将每个条目写入其自己的文件)。对于大数据,我经常选择将字典表示为我的文件系统上的一个目录,并让每个条目都是一个文件。 klepto 还提供多种缓存算法(如mrulrulfu 等)来帮助您管理您的内存缓存,并将使用该算法进行转储和加载到存档后端给你。

>>> from klepto.archives import dir_archive
>>> d = {'a':1, 'b':2, 'c':map, 'd':None}
>>> # map a dict to a filesystem directory
>>> demo = dir_archive('demo', d, serialized=True) 
>>> demo['a']
1
>>> demo['c']
<built-in function map>
>>> demo          
dir_archive('demo', {'a': 1, 'c': <built-in function map>, 'b': 2, 'd': None}, cached=True)
>>> # is set to cache to memory, so use 'dump' to dump to the filesystem 
>>> demo.dump()
>>> del demo
>>> 
>>> demo = dir_archive('demo', {}, serialized=True)
>>> demo
dir_archive('demo', {}, cached=True)
>>> # demo is empty, load from disk
>>> demo.load()
>>> demo
dir_archive('demo', {'a': 1, 'c': <built-in function map>, 'b': 2, 'd': None}, cached=True)
>>> demo['c']
<built-in function map>
>>> 

klepto 还提供内存映射文件后端的使用,以实现快速读写。还有其他标志,例如compression,可用于进一步自定义数据的存储方式。使用(MySQL 等)数据库作为后端而不是文件系统同样容易(完全相同的界面)。您可以使用标志cached=False 完全关闭内存缓存,并直接从磁盘或数据库读取和写入。

>>> from klepto.archives import dir_archive
>>> # does not hold entries in memory, each entry will be stored on disk
>>> demo = dir_archive('demo', {}, serialized=True, cached=False)
>>> demo['a'] = 10
>>> demo['b'] = 20
>>> demo['c'] = min
>>> demo['d'] = [1,2,3]

在此处获取kleptohttps://github.com/uqfoundation

【讨论】:

    【解决方案3】:

    也许你可以使用 sqlite3?除非你有真正的旧版 Python,否则它应该可用:https://docs.python.org/2/library/sqlite3.html

    我没有检查过 sqlite3 的限制,我不知道它在你的情况下的用处,但值得一试。

    【讨论】:

    • 我想过,但需要对代码进行相当多的修改。不过感谢您的建议。
    【解决方案4】:

    当您腌制整个数据结构时,您会受到系统 RAM 的限制。但是,您可以分块进行。

    streaming-pickle 看起来像是一种用于腌制大于板上内存的类文件对象的解决方案。

    https://gist.github.com/hardbyte/5955010

    【讨论】:

      【解决方案5】:

      由于它是一个字典,您可以将其转换为键值对列表 ([(k, v)])。然后,您可以使用您喜欢的任何技术(如 pickle)将每个元组序列化为字符串,并将它们逐行存储到文件中。这样,并行化进程、检查文件内容等也更容易。

      有些库允许您使用单个对象进行流式传输,但 IMO 只会让它变得更加复杂。只需一行一行地存储它就可以消除这么多的麻烦。

      【讨论】:

      • 我认为当 shelve 已经这样做时这过于复杂了。
      • 逐行存储东西对我来说似乎并不过分复杂。如果你使用搁置,你就会被搁置。例如,如果您逐行存储 JSON,那么几乎任何技术(如 Pig、Hive)都可以读取它。当数据变得非常大并且您不需要随机访问时,DBM 文件也不是最好的。使用head 等工具可以轻松检查逐行文件,可以更节省空间并且更难损坏。
      猜你喜欢
      • 1970-01-01
      • 2016-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-15
      • 1970-01-01
      • 2015-03-11
      相关资源
      最近更新 更多