В моем приложении мне нужен быстрый поиск атрибутов.В этом случае атрибуты представляют собой композицию строки и список словарей.Эти атрибуты хранятся в классе оболочки.Давайте назовем этот класс-оболочку 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.Каждый из этих планов может быть доступен с помощью универсального уникального идентификатора (uuid).Что мне нужно, так это быстрый поиск: с учетом uuid, что такое самолет.Естественное решение - это диктат.Простой класс для генерации самолетов с uuids в dict и для сохранения этого 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)
Что происходит, так это то, что много памяти расходуется!Если я проверим размер моего pl
объекта с помощью метода getsize () из этого вопроса , я получу на моей 64-битной машине значение 1 087 286 831 байт.Глядя на htop, моя потребность в памяти кажется еще выше (около 2 ГБ). В этом вопросе достаточно хорошо объяснено, почему словарям python требуется много памяти.
Тем не менее, я думаю, что это не должно иметь место в моей заявке.Объект плоскости, созданный в методе PlaneLookup.generate (), очень часто содержит одинаковые атрибуты (то есть одно и то же имя и одинаковые свойства).Таким образом, должна быть возможность сохранить этот объект один раз в dict и всякий раз, когда снова создается тот же объект (то же имя, тот же атрибут), сохраняется только ссылка на уже существующую запись dict.Поскольку простой объект Plane имеет размер 1147 байт (согласно методу getsize()
), простое сохранение ссылок может сэкономить много памяти!
Вопрос сейчас: как мне это сделать?В конце мне нужна функция, которая принимает uuid в качестве входных данных и возвращает соответствующий объект Plane
как можно быстрее с минимальным объемом памяти.Может быть, lru_cache может помочь?
Вот снова полный код для игры: https://pastebin.com/iTZyQQAU