Есть ли библиотека кеширования Python?


123

Я ищу библиотеку кеширования Python, но пока ничего не могу найти. Мне нужен простой dictинтерфейс, в котором я могу установить ключи и срок их действия и вернуть их в кеш. Что-то вроде:

cache.get(myfunction, duration=300)

который предоставит мне элемент из кеша, если он существует, или вызовет функцию и сохранит ее, если ее нет или срок ее действия истек. Кто-нибудь знает что-то подобное?


Я думаю, что вам не хватает itemвашего примера.
SilentGhost,

Да, наверное, понадобится ключ ... И, 2.x.
Ставрос Корокитакис

3
в рамках одного процесса или совместно между процессами? резьбовой или нет?
Аарон Уоттерс,

1
Это должно быть потокобезопасным, извините, я должен был упомянуть. Мне не нужно делиться между процессами.
Ставрос Корокитакис

6
Попробуйте DiskCache : лицензированный Apache2, 100% покрытие, потокобезопасность, безопасность процессов, множественные политики выселения и быстрая (тесты) .
GrantJ

Ответы:


52

Ах, я продолжал искать это, и все, что я нашел, было вики, в которой упоминалось, как использовать его в качестве промежуточного программного обеспечения WSGI. Похоже, что мне нужно, спасибо.
Ставрос Корокитакис

7
См. Также собачью кучу - предположительно новый улучшенный стакан.
s29,

72

Начиная с Python 3.2, вы можете использовать декоратор @lru_cache из библиотеки functools . Это последний недавно использованный кеш, поэтому для элементов в нем нет срока годности, но в качестве быстрого взлома он очень полезен.

from functools import lru_cache

@lru_cache(maxsize=256)
def f(x):
  return x*x

for x in range(20):
  print f(x)
for x in range(20):
  print f(x)

20
cachetools предлагает прекрасную реализацию этих функций, и он совместим с python 2 и python 3.
vaab

1
большой +1 для cachetools ... кажется довольно крутым и имеет парочку дополнительных алгоритмов кеширования :)
Йорн Хис

Это никогда не следует предлагать! Оставайтесь совместимыми.
PascalVKooten

1
@roboslone, два года (минус 4 дня ..) после вашего комментария о небезопасном потоке, возможно, он изменился. У меня есть cachetools 2.0.0, и я вижу в коде, что он использует RLock. /usr/lib/python2.7/site-packages/cachetools/func.py
Motty

@Motty: В документации для cachetools 4.0.0.0 сказано следующее: «Имейте в виду, что все эти классы не являются потокобезопасными . Доступ к общему кэшу из нескольких потоков должен быть правильно синхронизирован, например, с помощью одного из мемоизирующих декораторов с подходящий объект замка »(жирный шрифт)
Мартино

28

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


Это умно. Несколько изменений, и декоратор может даже истечь через установленное время.
Этеш Чоудхури,

Вы определенно можете записать ограничение на размер кеша в декораторе. Это было бы полезно, если бы вы хотели, чтобы функция, например, генерировала последовательность Фибоначчи построчно. Вам нужно кеширование, но вам нужны только последние два значения - сохранение всех из них просто неэффективно.
reem

14

Joblib https://joblib.readthedocs.io поддерживает функции кэширования в шаблоне Memoize. В основном идея состоит в том, чтобы кэшировать дорогостоящие в вычислительном отношении функции.

>>> from joblib import Memory
>>> mem = Memory(cachedir='/tmp/joblib')
>>> import numpy as np
>>> square = mem.cache(np.square)
>>> 
>>> a = np.vander(np.arange(3)).astype(np.float)
>>> b = square(a)                                   
________________________________________________________________________________
[Memory] Calling square...
square(array([[ 0.,  0.,  1.],
       [ 1.,  1.,  1.],
       [ 4.,  2.,  1.]]))
___________________________________________________________square - 0...s, 0.0min

>>> c = square(a)

Вы также можете делать необычные вещи, например использовать декоратор @ memory.cache для функций. Документация находится здесь: https://joblib.readthedocs.io/en/latest/generated/joblib.Memory.html


2
Кстати, joblib действительно эффективен, когда вы работаете с большими массивами NumPy, поскольку у него есть специальные методы для работы с ними.
alexbw

12

Еще никто не упомянул полку. https://docs.python.org/2/library/shelve.html

Это не memcached, но выглядит намного проще и может соответствовать вашим потребностям.


Я написал безопасную многопроцессорную оболочку для стандартного модуля полки (включая вспомогательную функцию для кеширования HTTP-запросов) на случай, если это будет полезно для всех: github.com/cristoper/shelfcache
cristoper

9

Я думаю, что python memcached API является наиболее распространенным инструментом, но я сам не использовал его и не уверен, поддерживает ли он нужные вам функции.


3
Это промышленный стандарт, но все, что мне нужно, - это простой механизм хранения в памяти, который может содержать около 100 ключей, а memcached - это немного излишне. Но спасибо за ответ.
Ставрос Корокитакис

7
import time

class CachedItem(object):
    def __init__(self, key, value, duration=60):
        self.key = key
        self.value = value
        self.duration = duration
        self.timeStamp = time.time()

    def __repr__(self):
        return '<CachedItem {%s:%s} expires at: %s>' % (self.key, self.value, time.time() + self.duration)

class CachedDict(dict):

    def get(self, key, fn, duration):
        if key not in self \
            or self[key].timeStamp + self[key].duration < time.time():
                print 'adding new value'
                o = fn(key)
                self[key] = CachedItem(key, o, duration)
        else:
            print 'loading from cache'

        return self[key].value



if __name__ == '__main__':

    fn = lambda key: 'value of %s  is None' % key

    ci = CachedItem('a', 12)
    print ci 
    cd = CachedDict()
    print cd.get('a', fn, 5)
    time.sleep(2)
    print cd.get('a', fn, 6)
    print cd.get('b', fn, 6)
    time.sleep(2)
    print cd.get('a', fn, 7)
    print cd.get('b', fn, 7)

5
Я сделал что-то подобное, но вам нужны блокировки для многопоточности и параметр размера, чтобы он не увеличивался бесконечно. Тогда вам понадобится какая-то функция для сортировки ключей по доступам, чтобы отбросить наименее используемые и т. Д. И т. Д.
Ставрос Корокитакис

Магнезии линия неправильна (следует использовать self.timeStamp). К тому же это плохая реализация, которая без нужды выполняет вычисления для каждого метода get (). Срок действия должен быть рассчитан в файле инициализации CachedItem.
ivo

1
Фактически, если вы реализуете только getметод, это не должен быть подкласс dict, это должен быть объект со встроенным dict.
ivo

6

Вы можете воспользоваться моим простым решением проблемы. Это действительно просто, ничего особенного:

class MemCache(dict):
    def __init__(self, fn):
        dict.__init__(self)
        self.__fn = fn

    def __getitem__(self, item):
        if item not in self:
            dict.__setitem__(self, item, self.__fn(item))
        return dict.__getitem__(self, item)

mc = MemCache(lambda x: x*x)

for x in xrange(10):
    print mc[x]

for x in xrange(10):
    print mc[x]

Ему действительно не хватает функциональности по истечении срока действия, но вы можете легко расширить его, указав конкретное правило в MemCache c-tor.

Код Hope достаточно понятен, но если нет, просто упомяну, что в этот кеш передается функция перевода в качестве одного из параметров c-tor. Он, в свою очередь, используется для создания кэшированного вывода относительно ввода.

Надеюсь, поможет


1
+1 за предложение чего-то простого. В зависимости от проблемы, это может быть просто инструмент для работы. PS Вам не нужен elseв __getitem__:)
hiwaylon

Почему бы ему не нужно elseв __getitem__? Вот где он заполняет
диктатор

5

Попробуйте redis, это одно из самых чистых и простых решений для приложений для атомарного обмена данными или если у вас есть платформа веб-сервера. Его очень легко настроить, вам понадобится клиент python redis http://pypi.python.org/pypi/redis


1
Следует упомянуть, что это вне процесса, для доступа к нему необходимо использовать TCP.
Джеффри Коппс


2

Этот проект направлен на обеспечение "Кэширования для людей" (хотя, похоже, это довольно неизвестно)

Некоторая информация со страницы проекта:

Монтаж

кеш установки pip

Использование:

import pylibmc
from cache import Cache

backend = pylibmc.Client(["127.0.0.1"])

cache = Cache(backend)

@cache("mykey")
def some_expensive_method():
    sleep(10)
    return 42

# writes 42 to the cache
some_expensive_method()

# reads 42 from the cache
some_expensive_method()

# re-calculates and writes 42 to the cache
some_expensive_method.refresh()

# get the cached value or throw an error
# (unless default= was passed to @cache(...))
some_expensive_method.cached()


-5

keyring - лучшая библиотека кеширования Python. Ты можешь использовать

keyring.set_password("service","jsonkey",json_res)

json_res= keyring.get_password("service","jsonkey")

json_res= keyring.core.delete_password("service","jsonkey")

Это библиотека ключей, а не библиотека кеширования.
Ставрос Корокитакис

@StavrosKorokithakis На самом деле я реализовал кэширование ключей через связку ключей
imp
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.