Умное кеширование дорогих объектов в Python - PullRequest
1 голос
/ 03 января 2012

У меня есть каталог изображений по порядку. Как правило, мой код будет использовать данные из последовательного подмножества изображений (например, изображения 5-10), и наивные варианты для доступа к ним:

  1. Создайте объект-оболочку с методом, который загружает изображение при необходимости и считывает мои данные (например, значение в пикселях). Это занимает немного памяти, но будет медленным, так как каждый раз нужно будет загружать каждое изображение.

  2. Сохраните все изображения в памяти. Это будет быстро, но очевидно, что количество изображений, которое мы можем хранить, ограничено.

Я хотел бы найти:

  • Какой-то метод, с помощью которого я могу определить, как прочитать изображение, соответствующее индексу или пути, а затем разрешить мне доступ, скажем, magic_image_collection[index], не беспокоясь о том, собирается ли он вернуть объект в память или прочти это заново. В идеале это позволило бы хранить в памяти соответствующие изображения или n последние использованные изображения.

Ответы [ 2 ]

5 голосов
/ 03 января 2012

Вы можете расширить dict по умолчанию и использовать метод __missing__ для вызова функции загрузки, если ключ отсутствует:

class ImageDict(dict):
    def __missing__(self, key):
        self[key] = img = self.load(key)
        return img
    def load(self, key):
        # create a queue if not exist (could be moved to __init__)
        if not hasattr(self, '_queue'):
            self._queue = []
        # pop the oldest entry in the list and the dict
        if len(self._queue) >= 100:
            self.pop(self._queue.pop(0))
        # append this key as a newest entry in the queue
        self._queue.append(key)
        # implement image loading here and return the image instance
        print 'loading', key
        return 'Image for %s' % key

И вывод (загрузка происходит только тогда, когда ключ не существуетпока что.)

>>> d = ImageDict()
>>> d[3]
loading 3
'Image for 3'
>>> d[3]
'Image for 3'
>>> d['bleh']
loading bleh
'Image for bleh'
>>> d['bleh']
'Image for bleh'

Одна эволюция состояла бы в том, чтобы сохранить только последний N элемент в dict и очистить самые старые записи.Вы можете реализовать это, сохранив список ключей для заказа.

2 голосов
/ 03 января 2012

Слабые ссылки - это не то, что вам нужно - слабые ссылки - это способ ссылки на элемент, который позволяет сборщику мусора собирать (то есть уничтожать) референта, если существуют только слабые ссылки на него.Другими словами, если вы создаете и сохраняете только слабые ссылки для какого-либо объекта, он, скорее всего, будет быстро собираться мусором, и вы от этого не выиграете.

Я бы выбрал ваш вариант №1 выше,В современных операционных системах ОС поддерживает кэш-память недавно использованных файлов (или их частей) в памяти, что будет означать, что вам придется нести стоимость загрузки файла с диска один раз, но после этого последующий доступ кфайл будет таким же быстрым (или почти таким же), как если бы он был в памяти вашего приложения.Кэш FS обычно представляет собой кэш в стиле LRU, поэтому часто используемые элементы будут оставаться в памяти, а редко используемые элементы будут удалены (и впоследствии будут загружены с диска при необходимости).В большинстве случаев достаточно полагаться на реализацию операционной системы такого рода логики, а не писать свою собственную (тем более что вам не нужно писать и поддерживать код для этого!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...