将大型列表保存在内存中的替代方法(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
有非常快的 fromfile
和 tofile
方法来促进数据的来回移动。
即,基本上,假设例如无符号长数字,例如:
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
等),但如果您确实只需要 pop
和 append
,则应该使用此方法。
【讨论】:
【参考方案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)的主要内容,如果未能解决你的问题,请参考以下文章