Python önbelleğe alma kitaplığı var mı?


123

Bir Python önbelleğe alma kitaplığı arıyorum, ancak şu ana kadar hiçbir şey bulamıyorum. dictAnahtarları ve son kullanma tarihlerini ayarlayıp önbelleğe alabileceğim basit benzeri bir arayüze ihtiyacım var . Şunun gibi bir şey:

cache.get(myfunction, duration=300)

bu bana eğer varsa önbellekteki öğeyi verir veya işlevi çağırır ve yoksa veya süresi dolmuşsa depolar. Bunun gibi bir şey bilen var mı?


Sanırım itemörneğinizde eksiksiniz.
SilentGhost

Evet, bu muhtemelen bir anahtara ihtiyaç duyar ... Ve 2.x.
Stavros Korokithakis

3
aynı süreç içinde mi yoksa süreçler arasında mı paylaşılıyor? dişli mi değil mi?
Aaron Watters

1
İş parçacığı için güvenli olmalı, üzgünüm, söylemeliydim. İşlemler arasında paylaşmama gerek yok.
Stavros Korokithakis

6
DiskCache'yi deneyin : Apache2 lisanslı,% 100 kapsam, iş parçacığı güvenli, süreç güvenli, çoklu tahliye ilkeleri ve hızlı (kıyaslamalar) .
GrantJ

Yanıtlar:


52

Ah, bunu aramaya devam ettim ve bulduğum tek şey onun bir WSGI ara yazılımı olarak nasıl kullanılacağından bahseden bir wiki idi. İhtiyacım olan şey gibi görünüyor, teşekkür ederim.
Stavros Korokithakis

7
Ayrıca köpek yığınına bakın - sözde yeni ve geliştirilmiş beher.
s29

72

Python 3.2'den , functools kitaplığındaki dekoratör @lru_cache'yi kullanabilirsiniz . Bu, Son Kullanılan bir önbellektir, bu nedenle içindeki öğeler için son kullanma süresi yoktur, ancak hızlı bir hack olarak çok yararlıdır.

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 bunların güzel bir uygulamasını sunar ve python 2 ve python 3 ile uyumludur.
vaab

1
önbellek araçları için büyük +1 ... oldukça havalı görünüyor ve birkaç önbellek algoritması daha var :)
Jörn Hees

Bu asla önerilmemelidir! Uyumlu kalın.
PascalVKooten

1
@roboslone, iş parçacığının güvenli olmadığı hakkındaki yorumunuzdan iki yıl sonra (eksi 4 gün ..) değişmiş olabilir. Önbellek araçlarım var 2.0.0 ve kodda bir RLock kullandığını görüyorum. /usr/lib/python2.7/site-packages/cachetools/func.py
Motty

@Motty: dokümantasyon lütfen unutmayın": cachetools 4.0.0.0 için bu diyor bütün bu sınıflar evreli olmayan birden çok iş parçacığı paylaşılan önbelleğe Erişim düzgün örneğin bir ile memoizing dekoratörler birini kullanarak, senkronize edilmelidir. uygun kilit nesnesi "(kalın mayın)
martineau

28

Memoize dekoratörüne de bir göz atabilirsiniz . Muhtemelen çok fazla değişiklik yapmadan istediğiniz şeyi yapmasını sağlayabilirsiniz.


Zekice. Birkaç değişiklik ve dekoratör belirli bir süre sonra bile sona erebilir.
Ehtesh Choudhury

Dekoratördeki önbelleğe kesinlikle boşluk tabanlı bir sınır yazabilirsiniz. Örneğin, fibonacci dizisi terimini terime göre oluşturmak için bir işlev istiyorsanız bu yararlı olacaktır. Önbelleğe almak istiyorsunuz, ancak yalnızca son iki değere ihtiyacınız var - hepsini kaydetmek, alan verimsizdir.
2013

14

Joblib https://joblib.readthedocs.io , Memoize modelinde önbelleğe alma işlevlerini destekler. Çoğunlukla fikir, hesaplama açısından pahalı işlevleri önbelleğe almaktır.

>>> 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)

Ayrıca, işlevler üzerinde @ memory.cache dekoratörünü kullanmak gibi süslü şeyler de yapabilirsiniz. Belgeler burada: https://joblib.readthedocs.io/en/latest/generated/joblib.Memory.html


2
Bir yan not olarak, joblib, büyük NumPy dizileriyle çalışırken gerçekten parlıyor, çünkü özellikle onlarla başa çıkmak için özel yöntemler var.
alexbw


9

Python memcached API'sinin yaygın bir araç olduğunu düşünüyorum , ancak bunu kendim kullanmadım ve ihtiyacınız olan özellikleri destekleyip desteklemediğinden emin değilim.


3
Bu endüstri standardı, ancak tek istediğim 100 kadar anahtar tutabilen basit bir bellek içi depolama mekanizması ve memcached biraz fazla. Yine de cevap için teşekkürler.
Stavros Korokithakis

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
Ben de öyle bir şey yaptım ama sonsuza dek büyümesini önlemek için çoklu okuma için kilitlere ve bir boyut parametresine ihtiyacınız var. Daha sonra, en az erişilenleri vb.
Atmak için erişime

Repr hattı (self.timeStamp kullanmalıdır) hatalı. Ayrıca her get () için gereksiz yere matematik yapan zayıf bir uygulama. Geçerlilik süresi, CachedItem init'te hesaplanmalıdır.
ivo

1
Aslında, sadece getyöntemi uyguluyorsanız , bu bir dict alt sınıfı olmamalı, gömülü bir dikt içeren bir nesne olmalıdır.
ivo

6

Problem için benim basit çözümümü kullanabilirsiniz. Gerçekten basit, hiçbir şey fantezi değil:

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]

Gerçekten de sona erme işlevinden yoksundur, ancak MemCache önbelleğinde belirli bir kuralı belirleyerek bunu kolayca genişletebilirsiniz.

Umut kodu yeterince açıklayıcıdır, ancak değilse, sadece belirtmek gerekirse, önbelleğe c-tor parametrelerinden biri olarak bir çeviri işlevi geçiriliyor. Girişle ilgili olarak önbelleğe alınmış çıktı oluşturmak için kullanılır.

Umarım yardımcı olur


1
Basit bir şey önermek için +1. Soruna bağlı olarak, sadece iş için bir araç olabilir. PS Buna gerek yok elseiçinde __getitem__:)
hiwaylon

Neden gerek olmaz elseiçinde __getitem__?
Dikteyi

5

Redis'i deneyin, uygulamaların verileri atomik bir şekilde paylaşması için veya bir web sunucusu platformunuz varsa, en temiz ve en kolay çözümlerden biridir. Kurulumu çok kolay, bir python redis istemcisine ihtiyacınız olacak http://pypi.python.org/pypi/redis


1
Belirtilmesi gerekir ki, işlem dışıdır, TCP kullanılarak erişilmesi gerekir.
jeffry copps


2

Bu proje , "insanlar için önbelleğe alma" sağlamayı hedefliyor (yine de oldukça bilinmiyor gibi görünüyor)

Proje sayfasından bazı bilgiler:

Kurulum

pip yükleme önbelleği

Kullanımı:

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

anahtarlık en iyi python önbelleğe alma kitaplığıdır. Kullanabilirsiniz

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

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

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

Bu bir anahtarlık kitaplığı, önbelleğe alma kitaplığı değil.
Stavros Korokithakis

@StavrosKorokithakis Aslında, anahtarlık aracılığıyla anahtarların önbelleğe alınmasını uyguladım
imp
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.