Apakah ada pustaka cache Python?


123

Saya mencari pustaka cache Python tetapi sejauh ini tidak dapat menemukan apa pun. Saya memerlukan dictantarmuka seperti sederhana di mana saya dapat mengatur kunci dan masa berlakunya dan mengembalikannya ke cache. Semacam sesuatu seperti:

cache.get(myfunction, duration=300)

yang akan memberi saya item dari cache jika ada atau memanggil fungsi dan menyimpannya jika tidak atau telah kedaluwarsa. Apakah ada yang tahu sesuatu seperti ini?


saya pikir Anda hilang itemdalam contoh Anda.
SilentGhost

Ya, ini mungkin membutuhkan kunci ... Dan, 2.x.
Stavros Korokithakis

3
dalam proses yang sama atau dibagi antar proses? berulir atau tidak?
Aaron Watters

1
Ini harus thread-safe, maaf, seharusnya saya sebutkan. Saya tidak perlu berbagi antar proses.
Stavros Korokithakis

6
Coba DiskCache : berlisensi Apache2, cakupan 100%, aman utas, aman proses, kebijakan penggusuran ganda, dan cepat (tolok ukur) .
GrantJ

Jawaban:



72

Dari Python 3.2 Anda dapat menggunakan dekorator @lru_cache dari pustaka functools. Ini adalah cache yang Terakhir Digunakan Baru-Baru Ini, jadi tidak ada waktu kedaluwarsa untuk item di dalamnya, tetapi sebagai peretasan cepat, ini sangat berguna.

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 menawarkan implementasi yang bagus dari ini dan itu kompatibel dengan python 2 dan python 3.
vaab

1
+1 besar untuk cachetools ... tampaknya cukup keren dan memiliki beberapa algoritme caching lainnya :)
Jörn Hees

Ini tidak boleh disarankan! Tetap kompatibel.
PascalVKooten

1
@roboslone, dua tahun (minus 4 hari ..) sejak komentar Anda tentang tidak amannya utas, mungkin telah berubah. Saya memiliki cachetools 2.0.0 dan saya melihat di kode yang menggunakan RLock. /usr/lib/python2.7/site-packages/cachetools/func.py
Motty

@Motty: Dokumentasi untuk cachetools 4.0.0.0 mengatakan ini: "Perlu diketahui bahwa semua kelas ini tidak aman untuk thread . Akses ke cache bersama dari beberapa thread harus disinkronkan dengan benar, misalnya dengan menggunakan salah satu dekorator memo dengan benda kunci yang sesuai "(tambang tebal)
martineau

28

Anda juga dapat melihat dekorator Memoize . Anda mungkin bisa membuatnya melakukan apa yang Anda inginkan tanpa terlalu banyak modifikasi.


Itu pintar. Sedikit perubahan dan dekorator bahkan bisa kedaluwarsa setelah waktu yang ditentukan.
Ehtesh Choudhury

Anda pasti bisa menulis batas berbasis ruang ke cache di dekorator. Itu akan sangat membantu jika Anda menginginkan suatu fungsi, misalnya, menghasilkan istilah urutan fibonacci. Anda ingin menyimpan ke cache, tetapi Anda hanya memerlukan dua nilai terakhir - menyimpan semuanya hanya tidak efisien ruang.
reem

14

Joblib https://joblib.readthedocs.io mendukung fungsi cache dalam pola Memoize. Sebagian besar, idenya adalah untuk menyimpan fungsi-fungsi yang mahal secara komputasi.

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

Anda juga dapat melakukan hal-hal mewah seperti menggunakan dekorator @ memory.cache pada fungsi. Dokumentasinya ada di sini: https://joblib.readthedocs.io/en/latest/generated/joblib.Memory.html


2
Sebagai catatan samping, joblib benar-benar bersinar saat Anda bekerja dengan array NumPy yang besar, karena ia memiliki metode khusus untuk menangani mereka secara khusus.
alexbw


9

Saya pikir API memcached python adalah alat yang lazim, tetapi saya belum menggunakannya sendiri dan tidak yakin apakah itu mendukung fitur yang Anda butuhkan.


3
Itu adalah standar industri, tetapi yang saya inginkan hanyalah mekanisme penyimpanan dalam memori sederhana yang dapat menampung 100 kunci atau lebih, dan memcache agak berlebihan. Terima kasih atas jawabannya.
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
Saya melakukan sesuatu seperti itu, tetapi Anda memerlukan kunci untuk multithreading dan parameter ukuran untuk menghindarinya tumbuh tanpa batas. Maka Anda memerlukan beberapa fungsi untuk mengurutkan kunci dengan akses untuk membuang kunci yang paling
jarang

Baris repr salah (harus menggunakan self.timeStamp). Selain itu, ini adalah implementasi yang buruk yang tidak perlu melakukan matematika untuk setiap get (). Waktu kedaluwarsa harus dihitung di CachedItem init.
ivo

1
Faktanya, jika Anda hanya mengimplementasikan getmetode, ini seharusnya tidak menjadi subkelas dict, itu haruslah sebuah objek dengan dict yang disematkan.
ivo

6

Anda dapat menggunakan solusi sederhana saya untuk masalah ini. Ini sangat mudah, tidak ada yang mewah:

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]

Memang tidak memiliki fungsi kedaluwarsa, tetapi Anda dapat dengan mudah memperluasnya dengan menetapkan aturan tertentu di c-tor MemCache.

Kode harapan cukup jelas, tetapi jika tidak, hanya untuk menyebutkan, cache itu diteruskan fungsi terjemahan sebagai salah satu parameter c-tornya. Ini digunakan pada gilirannya untuk menghasilkan output yang di-cache mengenai input.

Semoga membantu


1
1 untuk menyarankan sesuatu yang sederhana. Bergantung pada masalahnya, itu mungkin hanya alat untuk pekerjaan itu. NB Anda tidak perlu elsemasuk __getitem__:)
hiwaylon

Mengapa dia tidak perlu elsedi __getitem__? Di situlah dia mengisi
dikt

5

Coba redis, ini adalah salah satu solusi terbersih dan termudah bagi aplikasi untuk berbagi data secara atomic atau jika Anda memiliki beberapa platform server web. Sangat mudah untuk mengaturnya, Anda memerlukan klien python redis http://pypi.python.org/pypi/redis


1
Harus disebutkan, Ini keluar dari proses, perlu diakses menggunakan TCP.
jeffry copps


2

Proyek ini bertujuan untuk menyediakan "Caching untuk manusia" (sepertinya cukup tidak diketahui)

Beberapa info dari halaman proyek:

Instalasi

pip instal cache

Pemakaian:

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 adalah pustaka cache python terbaik. Kamu bisa memakai

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

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

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

Itu adalah perpustakaan keyring, bukan perpustakaan cache.
Stavros Korokithakis

@StavrosKorokithakis Sebenarnya, saya mengimplementasikan caching kunci melalui keyring
imp
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.