在我的应用程序中,我需要快速查找属性。在这种情况下,属性是字符串和字典列表的组合。这些属性存储在包装类中。让我们调用这个包装类Plane
:
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}])
为了更好地使用这个类,我添加了一个简单的类方法来通过提供和整数来构造实例。
所以现在在我的应用程序中我有许多飞机,大约10,000,000。可以通过通用唯一ID(uuid)访问这些平面中的每一个。我需要的是快速查找:给定一个uuid,什么是Plane。自然的解决方案是一个字典。在dict中使用uuids生成平面并将此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()方法from this question检查pl
对象的大小,我的64位机器上的值为1,087,286,831字节。看看htop,我的内存需求似乎更高(约2GB)。
In this question,很好地解释了为什么python词典需要很多内存。
但是,我认为在我的申请中不一定是这种情况。在PlaneLookup.generate()方法中创建的平面对象通常包含相同的属性(即相同的名称和相同的属性)。因此,必须可以在dict中保存此对象一次,并且每当再次创建相同的对象(相同名称,相同属性)时,仅存储对已存在的dict条目的引用。由于一个简单的Plane对象的大小为1147字节(根据getsize()
方法),只需保存引用可以节省大量内存!
现在的问题是:我该怎么做?最后,我需要一个函数,它将uuid作为输入,并尽可能快地返回相应的Plane
对象。
也许lru_cache可以提供帮助吗?
以下是完整的代码: https://pastebin.com/iTZyQQAU
答案 0 :(得分:1)
您是否考虑使用另一个带有idx的字典 - >飞机吗?然后在self.plane_dict[plane_uuid]
中你只会存储idx而不是object。这将节省内存并加快您的应用程序,但您需要修改查找方法。