มีไลบรารีการแคช Python หรือไม่?


123

ฉันกำลังมองหาไลบรารีการแคช Python แต่ไม่พบอะไรเลย ฉันต้องการdictอินเทอร์เฟซที่เรียบง่ายซึ่งฉันสามารถตั้งค่าคีย์และวันหมดอายุและเรียกคืนแคชได้ เรียงลำดับเช่น:

cache.get(myfunction, duration=300)

ซึ่งจะให้รายการจากแคชแก่ฉันหากมีอยู่หรือเรียกใช้ฟังก์ชันและเก็บไว้หากไม่มีหรือหมดอายุ มีใครรู้เรื่องแบบนี้บ้าง?


ฉันคิดว่าคุณพลาดitemในตัวอย่างของคุณ
SilentGhost

ใช่นี่อาจต้องใช้คีย์ ... และ 2.x.
Stavros Korokithakis

3
ภายในกระบวนการเดียวกันหรือใช้ร่วมกันระหว่างกระบวนการ? เกลียวหรือไม่?
Aaron Watters

1
มันควรจะปลอดภัยสำหรับเธรดขอโทษฉันควรจะพูดถึง ฉันไม่จำเป็นต้องแบ่งปันระหว่างกระบวนการ
Stavros Korokithakis

6
ลองDiskCache : Apache2 ได้รับใบอนุญาตคุ้มครอง 100% ด้ายปลอดภัยกระบวนการปลอดภัยนโยบายขับไล่หลายและรวดเร็ว (มาตรฐาน)
GrantJ

คำตอบ:


52

อ่าฉันค้นหาสิ่งนี้ไปเรื่อย ๆ สิ่งที่ฉันพบคือวิกิที่กล่าวถึงวิธีใช้เป็นมิดเดิลแวร์ WSGI ดูเหมือนว่าฉันต้องการอะไรขอบคุณ
Stavros Korokithakis

7
ดูเพิ่มเติมที่dogpile - ควรจะเป็นบีกเกอร์ใหม่และปรับปรุงใหม่
29

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 ... ดูค่อนข้างดีและมีอัลกอริธึมการแคชอีกสองสามรายการ :)
Jörn Hees

สิ่งนี้ไม่ควรแนะนำ! เข้ากันได้
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 ระบุว่า: "โปรดทราบว่าคลาสเหล่านี้ทั้งหมดไม่ปลอดภัยต่อเธรดการเข้าถึงแคชที่ใช้ร่วมกันจากหลายเธรดจะต้องซิงโครไนซ์อย่างถูกต้องเช่นโดยใช้หนึ่งในผู้ตกแต่งบันทึกช่วยจำกับ a วัตถุล็อคที่เหมาะสม"(ของฉันตัวหนา)
martineau

28

นอกจากนี้คุณอาจจะดูที่เป็นมัณฑนากร memoize คุณอาจได้รับมันเพื่อทำสิ่งที่คุณต้องการโดยไม่ต้องปรับเปลี่ยนมากเกินไป


ที่ฉลาด การเปลี่ยนแปลงเล็กน้อยและมัณฑนากรอาจหมดอายุหลังจากเวลาที่กำหนด
Ehtesh Choudhury

คุณสามารถเขียนขีด จำกัด ตามพื้นที่ไปยังแคชในมัณฑนากรได้ ซึ่งจะเป็นประโยชน์หากคุณต้องการให้ฟังก์ชันสร้างคำลำดับ fibonacci ตามระยะ คุณต้องการแคช แต่คุณต้องการเพียงสองค่าสุดท้าย - การประหยัดทั้งหมดเป็นเพียงพื้นที่ว่าง
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

ยังไม่มีใครพูดถึง Shelve https://docs.python.org/2/library/shelve.html

ไม่ใช่ memcached แต่ดูง่ายกว่ามากและอาจเหมาะกับความต้องการของคุณ


ฉันเขียนกระดาษห่อหุ้มเธรดและหลายกระบวนการที่ปลอดภัยสำหรับโมดูลชั้นวางมาตรฐาน (รวมถึงฟังก์ชันตัวช่วยสำหรับการแคชคำขอ http) ในกรณีที่มีประโยชน์สำหรับทุกคน: github.com/cristoper/shelfcache
cristoper

9

ฉันคิดว่าpython memcached APIเป็นเครื่องมือที่แพร่หลาย แต่ฉันไม่ได้ใช้ด้วยตัวเองและไม่แน่ใจว่ามันรองรับคุณสมบัติที่คุณต้องการหรือไม่


3
นั่นคือมาตรฐานอุตสาหกรรม แต่สิ่งที่ฉันต้องการคือกลไกการจัดเก็บข้อมูลในหน่วยความจำที่เรียบง่ายซึ่งสามารถเก็บคีย์ได้ 100 คีย์หรือมากกว่านั้นและ memcached นั้นค่อนข้างมากเกินไป ขอบคุณสำหรับคำตอบแม้ว่า
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
ฉันทำอะไรแบบนั้น แต่คุณต้องล็อคสำหรับมัลติเธรดและพารามิเตอร์ขนาดเพื่อหลีกเลี่ยงไม่ให้มันเติบโตอย่างไม่สิ้นสุด จากนั้นคุณต้องมีฟังก์ชั่นบางอย่างเพื่อจัดเรียงคีย์โดยการเข้าถึงเพื่อละทิ้งคีย์ที่เข้าถึงน้อยที่สุด ฯลฯ ฯลฯ ...
Stavros Korokithakis

Reprบรรทัดไม่ถูกต้อง (ควรใช้ self.timeStamp) ที่ นอกจากนี้ยังเป็นการใช้งานที่ไม่ดีซึ่งไม่จำเป็นต้องใช้คณิตศาสตร์สำหรับทุก ๆ get () ควรคำนวณเวลาหมดอายุใน CachedItem init
ivo

1
ในความเป็นจริงหากคุณใช้getวิธีนี้เพียงอย่างเดียวนี่ไม่ควรเป็นคลาสย่อยของ 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]

มันไม่มี funcionality การหมดอายุ แต่คุณสามารถขยายได้อย่างง่ายดายโดยระบุกฎเฉพาะใน MemCache c-tor

รหัสความหวังนั้นอธิบายตัวเองได้เพียงพอ แต่ถ้าไม่เพียงแค่พูดถึงแคชนั้นจะถูกส่งผ่านฟังก์ชันการแปลเป็นหนึ่งในพารามิเตอร์ c-tor ใช้เพื่อสร้างเอาต์พุตแคชเกี่ยวกับอินพุต

หวังว่าจะช่วยได้


1
+1 เพื่อแนะนำสิ่งง่ายๆ ขึ้นอยู่กับปัญหานั้นอาจเป็นเพียงเครื่องมือสำหรับงาน PS คุณไม่จำเป็นต้องใช้elseใน__getitem__:)
hiwaylon

ทำไมเขาไม่จำเป็นต้องelseอยู่ในนั้น__getitem__? นั่นคือที่ที่เขาเติมคำสั่ง ...
Nils Ziehn

5

ลองใช้ redis ซึ่งเป็นหนึ่งในโซลูชันที่สะอาดและง่ายที่สุดสำหรับแอปพลิเคชันในการแบ่งปันข้อมูลแบบปรมาณูหรือหากคุณมีแพลตฟอร์มเว็บเซิร์ฟเวอร์ ติดตั้งง่ายมากคุณจะต้องมีไคลเอนต์ python redis http://pypi.python.org/pypi/redis


1
ควรกล่าวถึงมันอยู่นอกกระบวนการจำเป็นต้องเข้าถึงโดยใช้ TCP
jeffry copps


2

โครงการนี้มีจุดมุ่งหมายเพื่อให้ "Caching for human" (ดูเหมือนจะไม่ค่อยเป็นที่รู้จักนัก)

ข้อมูลบางส่วนจากหน้าโครงการ:

การติดตั้ง

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

นั่นคือไลบรารีพวงกุญแจไม่ใช่ไลบรารีแคช
Stavros Korokithakis

@StavrosKorokithakis จริงๆแล้วฉันใช้การแคชคีย์ผ่านพวงกุญแจ
imp
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.