Python 如何减少字典的内存占用?

Python 如何减少字典的内存占用?,python,python-3.x,dictionary,Python,Python 3.x,Dictionary,在我的应用程序中,我需要快速查找属性。在本例中,属性是字符串和字典列表的组合。这些属性存储在包装器类中。让我们调用这个包装类平面: class Plane(object): def __init__(self, name, properties): self.name = name self.properties = properties @classmethod def from_idx(cls, idx): if id

在我的应用程序中,我需要快速查找属性。在本例中,属性是字符串和字典列表的组合。这些属性存储在包装器类中。让我们调用这个包装类
平面

class Plane(object):
    def __init__(self, name, properties):
        self.name = name
        self.properties = properties

    @classmethod
    def from_idx(cls, idx):
        if idx == 0:
            return cls("PaperPlane", [{"canFly": True}, {"isWaterProof": False}])
        if idx == 1:
            return cls("AirbusA380", [{"canFly": True}, {"isWaterProof": True}, {"hasPassengers": True}])
为了更好地使用这个类,我添加了一个简单的classmethod,通过提供和integer来构造实例

所以现在在我的应用程序中,我有许多飞机,大约10000000架。每个平面都可以通过通用唯一id(uuid)访问。我需要的是快速查找:给定uuid,平面是什么。自然的解决方案是dict。在dict中生成带有UUID的平面并将该dict存储在文件中的简单类可能如下所示:

class PlaneLookup(object):
    def __init__(self):
        self.plane_dict = {}

    def generate(self, n_planes):
        for i in range(n_planes):
            plane_id = uuid.uuid4().hex
            self.plane_dict[plane_id] = Plane.from_idx(np.random.randint(0, 2))

    def save(self, filename):
        with gzip.open(filename, 'wb') as f:
            pickle.dump(self.plane_dict, f, pickle.HIGHEST_PROTOCOL)

    @classmethod
    def from_disk(cls, filename):
        pl = cls()
        with gzip.open(filename, 'rb') as f:
            pl.plane_dict = pickle.load(f)
        return pl
那么现在发生的是,如果我生成一些平面

pl = PlaneLookup()
pl.generate(1000000)
结果是,大量的内存被消耗掉了!如果我用getsize()方法检查
pl
对象的大小,我在64位机器上得到的值为1087286831字节。看看htop,我的内存需求似乎更高(大约2GB)。 ,很好地解释了python词典需要大量内存的原因

然而,我认为我的申请不一定是这样。在PlaneLookup.generate()方法中创建的平面对象通常包含相同的属性(即相同的名称和相同的属性)。因此,必须能够在dict中保存此对象一次,并且每当再次创建相同的对象(相同的名称、相同的属性)时,只存储对已经存在的dict条目的引用。由于简单平面对象的大小为1147字节(根据
getsize()
方法),因此仅保存引用可能会节省大量内存

现在的问题是:我如何做到这一点?最后,我需要一个函数,该函数将uuid作为输入,并以尽可能少的内存尽可能快地返回相应的
平面
对象。 也许lru缓存可以帮上忙

下面是要使用的完整代码:

你有没有想过再有一本idx->plane的字典?然后在
self.plane\u dict[plane\u uuid]
中,您只需存储idx而不是对象。这将节省内存并加快应用程序的速度,不过您需要修改查找方法。

平面是否应被视为不可变?您可以使用小型数据库吗?
Plane
似乎不需要是类,因为您没有任何方法。将每个
平面
表示为一个简单的元组可能是一个更好的主意。我建议使用Python的模块,它为基于文件的数据库提供了一个类似字典的接口,因此不需要将其全部存储在内存中。为什么要为
属性
存储单个元素
dict
对象的列表???这可能是您可能想到的最不有用的数据结构。只需使用一个
dict
,或者更好的方法是,在对象上创建单独的属性(不管怎么说,这基本上是一个dict…)我想我这里的示例不好。这是不可能的,因为可能存在不是由索引而是由类构造函数生成的平面。索引只是一个辅助函数。然后尝试让所有平面的注册表按实例生成和存储新索引。或者,仅当哈希不存在时,才使用
\uuuuu hash\uuuu
函数在注册表中存储平面,并将哈希存储在
平面dict
中。