2012-03-13 11 views
5

कमजोर मॉड्यूल के लिए आधिकारिक पायथन दस्तावेज़ के अनुसार "कमजोर संदर्भों के लिए प्राथमिक उपयोग कैश या मैपिंग को बड़ी वस्तुओं को पकड़ना है ..."। इसलिए, मैंने एक लंबे समय तक चलने वाले फ़ंक्शन के लिए कैशिंग तंत्र को लागू करने के लिए WeakValueDictionary का उपयोग किया। हालांकि, जैसा कि यह निकला, कैश में मूल्य तब तक नहीं रहे जब तक वे वास्तव में फिर से उपयोग नहीं किए जाते, लेकिन लगभग हर बार पुन: संकलित करने की आवश्यकता होती है। चूंकि WeakValueDictionary में संग्रहीत मानों तक पहुंच के बीच कोई मजबूत संदर्भ नहीं थे, इसलिए जीसी ने उनसे छुटकारा पा लिया (भले ही स्मृति के साथ बिल्कुल कोई समस्या नहीं थी)।कैश के लिए WeakValueDictionary का उपयोग करते समय जीसी के साथ समस्याएं

अब, कैश को लागू करने के लिए मुझे कमजोर संदर्भ सामग्री का उपयोग कैसे करना चाहिए? अगर मैं जीसी को अपने कमजोर संदर्भों को हटाने से स्पष्ट रूप से मजबूत संदर्भ रखता हूं, तो पहले स्थान पर वीकवेल्यू डिक्शनरी का उपयोग करने का कोई मतलब नहीं होगा। संभवतः जीसी के लिए कुछ विकल्प होना चाहिए जो इसे बताता है: स्मृति को समाप्त होने पर केवल कुछ संदर्भों और कमजोर संदर्भ वाले सभी चीज़ों को हटाएं (या कुछ थ्रेसहोल्ड पार हो गया है)। क्या ऐसा कुछ है? या इस तरह के कैश के लिए एक बेहतर रणनीति है?

उत्तर

3

कैशिंग लागू करने के लिए weakref मॉड्यूल का उपयोग करने के उदाहरण के साथ मैं आपकी पूछताछ का उत्तर देने का प्रयास करूंगा। हम weakref.WeakValueDictionary में हमारे कैश के कमजोर संदर्भों को रखेंगे, और collections.deque में मजबूत संदर्भ होंगे क्योंकि इसमें maxlen संपत्ति है जो नियंत्रित करती है कि यह कितनी ऑब्जेक्ट्स रखती है। समारोह बंद शैली में लागू:

import weakref, collections 
def createLRUCache(factory, maxlen=64): 
    weak = weakref.WeakValueDictionary() 
    strong = collections.deque(maxlen=maxlen) 

    notFound = object() 
    def fetch(key): 
     value = weak.get(key, notFound) 
     if value is notFound: 
      weak[key] = value = factory(key) 
     strong.append(value) 
     return value 
    return fetch 

deque वस्तु केवल बस पुरानी प्रविष्टियों के लिए संदर्भ छोड़ने पिछले maxlen प्रविष्टियों रखेंगे, एक बार यह क्षमता तक पहुँचता है। जब पुरानी प्रविष्टियां गिरा दी जाती हैं और पाइथन द्वारा एकत्रित कचरा, WeakValueDictionary मानचित्र से उन चाबियों को हटा देगा। इसलिए, दो वस्तुओं का संयोजन हमें हमारे एलआरयू कैश में केवल maxlen प्रविष्टियों को रखने में मदद करता है।

class Silly(object): 
    def __init__(self, v): 
     self.v = v 

def fib(i): 
    if i > 1: 
     return Silly(_fibCache(i-1).v + _fibCache(i-2).v) 
    elif i: return Silly(1) 
    else: return Silly(0) 
_fibCache = createLRUCache(fib) 
0

ऐसा लगता है कि कम से कम CPython 2.7 और 3.0 में इस सीमा को दूर करने का कोई तरीका नहीं है।

समाधान createLRUCache() पर अपनी प्रतिक्रिया व्यक्त:

createLRUCache साथ समाधान (कारखाने, maxlen = 64) मेरी उम्मीदों के साथ ठीक नहीं है। 'Maxlen' को बाध्य करने का विचार कुछ ऐसा है जो मैं टालना चाहता हूं। यह मुझे कुछ गैर स्केलेबल निरंतर निर्दिष्ट करने या कुछ ह्युरिस्टिक बनाने के लिए मजबूर करेगा, यह तय करने के लिए कि कौन सा निरंतर बेहतर है या मेजबान स्मृति सीमाएं।

मैं पसंद करेंगे जीसी नहीं सीधे WeakValueDictionary से unreferenced मूल्यों को खत्म होगा, लेकिन condition is used for regular GC पर:

आवंटन की संख्या शून्य से deallocations की संख्या threshold0 से अधिक हो, संग्रह शुरू होता है।