将大型列表保存在内存中的替代方法(python)

Posted

技术标签:

【中文标题】将大型列表保存在内存中的替代方法(python)【英文标题】:Alternatives to keeping large lists in memory (python) 【发布时间】:2010-12-31 15:33:08 【问题描述】:

如果我在 python 中有一个可能超出可用内存地址空间的列表(或数组、字典....),(32 位 python)有哪些选项和相对速度? (除了没有列出那么大的清单) 该列表可能超出记忆,但我无法事先知道。一旦它开始超过 75%,我不想再将列表保留在内存中(或者无论如何都是新项目),有没有办法在中途转换为基于文件的方法?

最好的(进出速度)文件存储选项是什么?

只需要存储一个简单的数字列表。无需随机访问第 N 个元素,只需追加/弹出类型的操作。

【问题讨论】:

【参考方案1】:

如果您的“数字”足够简单(每个最多 4 个字节的有符号或无符号整数,或者每个 4 或 8 个字节的浮点数),我推荐标准库 array 模块作为保持数百万它们在内存中(“虚拟数组”的“尖端”),并带有一个二进制文件(为二进制 R/W 打开)支持磁盘上的其余结构。 array.array 有非常快的 fromfiletofile 方法来促进数据的来回移动。

即,基本上,假设例如无符号长数字,例如:

import os

# no more than 100 million items in memory at a time
MAXINMEM = int(1e8)

class bigarray(object):
  def __init__(self):
    self.f = open('afile.dat', 'w+')
    self.a = array.array('L')
  def append(self, n):
    self.a.append(n)
    if len(self.a) > MAXINMEM:
      self.a.tofile(self.f)
      del self.a[:]
  def pop(self):
    if not len(self.a):
      try: self.f.seek(-self.a.itemsize * MAXINMEM, os.SEEK_END)
      except IOError: return self.a.pop()  # ensure normal IndexError &c
      try: self.a.fromfile(self.f, MAXINMEM)
      except EOFError: pass
      self.f.seek(-self.a.itemsize * MAXINMEM, os.SEEK_END)
      self.f.truncate()
    return self.a.pop()

当然,您可以根据需要添加其他方法(例如,跟踪总长度,添加 extend 等),但如果您确实只需要 popappend,则应该使用此方法。

【讨论】:

【参考方案2】:

可能有几十种方法可以将列表数据存储在文件中而不是内存中。您选择如何执行此操作将完全取决于您需要对数据执行哪种操作。您需要随机访问第 N 个元素吗?您需要遍历所有元素吗?您会搜索符合特定条件的元素吗?列表元素采用什么形式?你会只在列表的末尾插入,还是在中间?是否有元数据可以与磁盘上的大量项目一起保存在内存中?以此类推。

一种可能性是将数据结构化,并将其存储在 SQLite 数据库中。

【讨论】:

只需要存储简单的数字列表。无需随机访问第 N 个元素,只需追加和弹出类型操作。【参考方案3】:

答案是“视情况而定”。

您在列表中存储了什么?字符串?整数?对象?

与阅读列表相比,写入列表的频率如何?是只在末尾追加条目,还是可以在中间修改或插入条目?

如果您只是追加到末尾,那么写入平面文件可能是最简单的方法。

如果您要存储可变大小的对象(例如字符串),则可以保留每个字符串开头的内存索引,以便您快速阅读。

如果您想要字典行为,请查看 db 模块 - dbm、gdbm、bsddb 等。

如果您想要随机访问写入,那么 SQL 数据库可能会更好。

无论您做什么,访问磁盘都会比内存慢几个数量级,但如果不知道数据将如何使用,就不可能更具体。

编辑: 根据您更新的要求,我将使用一个平面文件并保留最后 N 个元素的内存缓冲区。

【讨论】:

【参考方案4】:

好吧,如果您正在寻找速度并且您的数据本质上是数字的,您可以考虑使用 numpy 和 PyTables 或 h5py。据我所知,界面不如简单的列表,但可扩展性很棒!

【讨论】:

【参考方案5】:

你检查了基于pickle的搁置python模块吗?

http://docs.python.org/library/shelve.html

【讨论】:

【参考方案6】:

您可能需要考虑另一种结构:不是列表,而是弄清楚如何使用生成器或自定义迭代器来完成(您的任务)。

【讨论】:

我正在尝试。但是我问这个问题是为了更普遍的应用。【参考方案7】:

你可以试试 blist: https://pypi.python.org/pypi/blist/

blist 是 Python 列表的直接替代品,可在修改大型列表时提供更好的性能。

【讨论】:

【参考方案8】:

现代操作系统会为您处理此问题,您无需担心。它被称为virtual memory。

【讨论】:

这是真的,但它真的很慢。另外,即使是虚拟内存也是有限的(如果他有一个非常大的数据集)。 list(combinations(1140, 17)) 填充可用内存地址空间(python 错误)不确定 VM 中发生了什么。据我所知,它从不使用它。我有超过 4gb 的内部内存,它没有填满它,因为 32 位有 4GB 的限制。不知道当达到限制时会发生什么,除了我得到一个错误。 使用垃圾收集语言你失去的一个东西(如果你曾经拥有它的话)是让虚拟内存系统“为你处理这个”的能力。 1/ 不能保证结构中 cons 单元的位置。 2/ 即使你没有,GC 也会访问它们。除非您非常幸运,否则虚拟内存在实现稀疏访问的数据结构方面从来都不是很好,但是对于 Python 中的任意数据结构,即使是运气也不够。 哦,我忘了,这个问题清楚地提到了地址空间的耗尽。虚拟内存仅有助于物理内存的耗尽(假设地址空间大于物理内存)。 两个厘米。 (0) 能不能用64位Python获得真正大的地址空间,并且依赖虚拟内存? (很难相信您可以通过手动将数据分页到文件来击败虚拟内存。) (1) 您必须combinations() 上调用list() 吗?如果可以对迭代器使用惰性求值,是否可以避免填满 RAM?【参考方案9】:

面向文档的数据库怎么样? 有几种选择;我认为目前最知名的是CouchDB,但您也可以选择Tokyo Cabinet,或MongoDB。最后一个的优点是直接从主项目绑定python,不需要任何额外的模块。

【讨论】:

以上是关于将大型列表保存在内存中的替代方法(python)的主要内容,如果未能解决你的问题,请参考以下文章

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

Python中类和对象在内存中是如何保存?

如何在 python 中遍历大型 CSV 文件时轻松使用内存?

保存 scikit-learn 分类器会导致内存错误

将成员保存在数据结构中的另一种方法

将大型 Python 数组保存到磁盘以供以后重复使用 --- hdf5?还有啥方法?