Pythonキャッシングライブラリはありますか?


123

Pythonキャッシングライブラリを探していますが、今のところ何も見つかりません。dictキーとその有効期限を設定して、それらをキャッシュに戻すことができるシンプルなインターフェースが必要です。次のようなもの:

cache.get(myfunction, duration=300)

存在する場合はキャッシュからアイテムを取得するか、関数を呼び出して、存在しない場合や期限が切れている場合は保存します。誰かがこのようなことを知っていますか?


itemあなたの例ではあなたが欠けていると思います。
SilentGhost 2009

はい、おそらくこれにはキーが必要です...そして、2.x。
Stavros Korokithakis

3
同じプロセス内またはプロセス間で共有?スレッドかどうか?
アーロンワッターズ

1
スレッドセーフである必要があります。申し訳ありません。プロセス間で共有する必要はありません。
Stavros Korokithakis、2009

6
DiskCacheを試してください:Apache2ライセンス、カバレッジ100%、スレッドセーフ、プロセスセーフ、複数のエビクションポリシー、高速(ベンチマーク)
GrantJ 2016年

回答:


52

ああ、これを探し続けたところ、WSGIミドルウェアとしての使い方を述べたwikiしか見つかりませんでした。必要なものに見えます、ありがとう。
Stavros Korokithakis 09/09/15

7
dogpileも参照してください-おそらく新しく改良されたビーカーです。
s29

72

Python 3.2 以降では、functoolsライブラリのデコレータ@lru_cacheを使用できます。これは最後に使用されたキャッシュなので、その中のアイテムに有効期限はありませんが、高速ハッキングとして非常に役立ちます。

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
cachetoolsにとって大きな+1は...かなりクールだとカップルより多くのキャッシュアルゴリズムを:)がある
ジョーンHEES

これは決して提案されるべきではありません!互換性を保ちます。
PascalVKooten 2017年

1
@roboslone、スレッドセーフではないというコメントから2年(マイナス4日..)、変更された可能性があります。cachetools 2.0.0を使用していますが、コードでRLockを使用していることがわかります。/usr/lib/python2.7/site-packages/cachetools/func.py
Motty

@Motty:cachetools 4.0.0.0 のドキュメントには次のように書かれています:「これらすべてのクラスはスレッドセーフではないことに注意してください。複数のスレッドからの共有キャッシュへのアクセスは適切に同期する必要があります。たとえば、適切なロックオブジェクト」(太字)
martineau

28

Memoizeデコレータご覧ください。あまり変更を加えずに、思い通りの動作をさせることができるでしょう。


それは賢いです。いくつかの変更とデコレータは、設定された時間後に期限切れになることさえありました。
Ehtesh Choudhury

デコレータのキャッシュにスペースベースの制限を確実に書き込むことができます。たとえば、用語ごとにフィボナッチ数列を生成する関数が必要な場合に役立ちます。キャッシングが必要ですが、必要なのは最後の2つの値だけです。それらすべてを保存すると、スペース効率が悪くなります。
2013年

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
余談ですが、大きなNumPy配列を操作している場合、joblibには特別に対処する特別なメソッドがあるため、joblibは本当に優れています。
alexbw 14

12

だれもまだ棚について言及していません。https://docs.python.org/2/library/shelve.html

memcachedではありませんが、はるかに単純に見え、ニーズに合う可能性があります。


誰にとっても役立つ場合に備えて、標準のシェルブモジュール(httpリクエストをキャッシュするヘルパー関数を含む)のスレッドおよびマルチプロセスセーフなラッパーを作成しました:github.com/cristoper/shelfcache
cristoper

9

はpython memcached APIが普及しているツールだと思いますが、私自身はそれを使用したことがなく、必要な機能をサポートしているかどうかはわかりません。


3
これは業界標準ですが、必要なのは100個程度のキーを保持できる単純なメモリ内ストレージメカニズムだけで、memcachedは少しやりすぎです。でも、答えてくれてありがとう。
Stavros Korokithakis 09/09/15

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
私はそのようなことをしましたが、それが無限に大きくなるのを避けるために、マルチスレッドのロックとサイズパラメータが必要です。そして、あなたは少なくとも-アクセスものを破棄するようにアクセスしてキーをソートするために、いくつかの機能を必要とする、などなど...
スタブロスKorokithakis

reprラインは(self.timeStampを使用する必要があります)間違っています。同様に、すべてのget()に対して不必要に数学を実行するのは貧弱な実装です。有効期限は、CachedItem initで計算する必要があります。
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で特定のルールを指定することで簡単に拡張できます。

コードは十分に自明ですが、そうではない場合でも、そのキャッシュにはc-torパラメータの1つとして変換関数が渡されます。次に、入力に関してキャッシュされた出力を生成するために使用されます。

それが役に立てば幸い


1
+1はシンプルなものを提案するためのものです。問題によっては、それは単に仕事のためのツールかもしれません。PSあなたは必要としないelse__getitem__:)
hiwaylon

なぜ彼はする必要はありませんelseでは__getitem__?それは彼が
口述書を作成するところ

5

redisを試してください。これは、アプリケーションがアトミックな方法でデータを共有するための最もクリーンで簡単なソリューションの1つ、またはWebサーバープラットフォームがある場合に使用します。設定は非常に簡単です。Pythonredisクライアントhttp://pypi.python.org/pypi/redisが必要です。


1
言及する必要があります。これはプロセス外であり、TCPを使用してアクセスする必要があります。
jeffry copps


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

キーリングは最高のpythonキャッシングライブラリです。使用できます

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

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

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

これはキーリングライブラリであり、キャッシュライブラリではありません。
Stavros Korokithakis 2013年

@StavrosKorokithakis実際、私はキーリングによるキーのキャッシュを実装しました
imp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.