2013-03-21 86 views
6

我使用Python集合集合来存储唯一对象。每个对象都覆盖了__hash____eq__Python非常大集。如何避免内存不足异常?

该集合包含近200 000个对象。该套件本身需要接近4 GB的内存。 它可以在超过5 GB的机器上正常工作,但现在我需要在只有3 GB可用RAM的机器上运行脚本。

我重写了一个脚本到C# - 实际上从同一个源读取相同的数据,把它放到CLR模拟集(HashSet),而不是4 GB,它花了近350 MB,而脚本执行的速度是相对相同(接近40秒)但我必须使用Python。

Q1:Python是否有任何“磁盘持久性”集或其他解决方法?我猜想它只能在内存中存储hash/eq方法中使用的“key”数据,而其他所有内容都可以保存到磁盘中。或者也许在Python中有其他解决方法来获得一个唯一的对象集合,这些对象可能会占用比系统中可用内存更多的内存。第二季度:较少实际的问题:为什么python集合为一组需要更多的内存?

我用标准的Python 2.7.3在64位的Ubuntu 12.10

谢谢。

UPDATE1: 什么脚本执行:

  1. 阅读了大量的半结构化JSON文件

  2. 分析每个(每个JSON与此相关的聚合对象集合包括序列化对象的) JSON文档从中检索主对象和聚合集合中的对象。每个解析对象都存储到一个集合中。 Set仅用于存储唯一对象。首先,我使用了一个数据库,但是数据库中的唯一约束条件使x100-x1000工作得更慢。每个JSON文档都被解析为1-8种不同的对象类型。每个对象类型都存储在它自己的集合中,以将唯一对象保存在内存中。

  3. 存储在集合中的所有数据都保存到具有唯一约束的关系数据库中。每组都存储在单独的数据库表中。

脚本以非结构化数据,删除汇总对象集合重复的JSON文件和结构化数据存储到关系型数据库的整体思路。

更新2:

2 delnan:我评论的所有代码行与添加到不同的组保持所有其他工作人员(中获取数据,解析,迭代)相同的 - 该脚本了4 GB的内存更少。

这意味着,当这些200K对象被添加到集合 - 他们开始占用这么多的内存。该对象是来自TMDB - ID,流派列表,演员名单,导演,许多其他电影细节以及可能来自维基百科的大型电影描述的简单电影数据。

+3

你为什么不使用数据库? – 2013-03-21 18:50:55

+0

对象包含什么类型的数据?你可以发布一些代码吗? – TAS 2013-03-21 18:54:37

+1

您可以尝试将它们存储在[shelve](http://docs.python.org/library/shelve.html)中,使用散列作为键。 – georg 2013-03-21 18:56:01

回答

4

集的确使用了大量的内存,但名单没有。

>>> from sys import getsizeof 
>>> a = range(100) 
>>> b = set(a) 
>>> getsizeof(a) 
872 
>>> getsizeof(b) 
8424 
>>> 

如果您使用套件的唯一原因是为了防止重复,我建议您使用列表来代替。您可以通过在添加对象之前测试对象是否已经在您的列表中来防止重复。它可能比使用内置机制更慢,但肯定会使用更少的内存。

2

尝试使用__slots__来减少您的内存使用量。

当我上次有很多很多对象出现这个问题时,使用__slots__将内存使用量减少到1/3。

这里是您可能感兴趣的SO question about __slots__

5

最好的方法可能是让你存储在集合中的对象更小。如果它们包含不必要的字段,请删除它们

为了减少一般对象的开销,你也可以使用__slots__声明中使用的字段:

class Person(object): 
    __slots__ = ['name', 'age'] 
    def __init__(self): 
     self.name = 'jack' 
     self.age = 99 
+0

假设CPython。 PyPy对大多数对象进行类似的优化,而无需指定'__slots__' IIRC。 – delnan 2013-03-21 19:02:19