2011-07-18 16 views
8

यह विधि डेटा बेस में शर्तों की एक सूची पर फिर से शुरू होती है, यह जांचें कि शर्तें तर्क के रूप में पारित पाठ में हैं या नहीं, और यदि कोई है, तो इसे खोज पृष्ठ के लिंक के साथ पैरामीटर के रूप में बदलें।यह पायथन विधि स्मृति को क्यों लीक कर रही है?

शब्दों की संख्या उच्च (लगभग 100000) है, इसलिए प्रक्रिया बहुत धीमी है, लेकिन यह ठीक है क्योंकि यह क्रॉन नौकरी के रूप में किया जाता है। हालांकि, यह बढ़ना करने के लिए स्क्रिप्ट स्मृति consumtion का कारण बनता है और मैं नहीं मिल सकता है क्यों:

class SearchedTerm(models.Model): 

[...] 

@classmethod 
def add_search_links_to_text(cls, string, count=3, queryset=None): 
    """ 
     Take a list of all researched terms and search them in the 
     text. If they exist, turn them into links to the search 
     page. 

     This process is limited to `count` replacements maximum. 

     WARNING: because the sites got different URLS schemas, we don't 
     provides direct links, but we inject the {% url %} tag 
     so it must be rendered before display. You can use the `eval` 
     tag from `libs` for this. Since they got different namespace as 
     well, we enter a generic 'namespace' and delegate to the 
     template to change it with the proper one as well. 

     If you have a batch process to do, you can pass a query set 
     that will be used instead of getting all searched term at 
     each calls. 
    """ 

    found = 0 

    terms = queryset or cls.on_site.all() 

    # to avoid duplicate searched terms to be replaced twice 
    # keep a list of already linkified content 
    # added words we are going to insert with the link so they won't match 
    # in case of multi passes 
    processed = set((u'video', u'streaming', u'title', 
        u'search', u'namespace', u'href', u'title', 
        u'url')) 

    for term in terms: 

     text = term.text.lower() 

     # no small word and make 
     # quick check to avoid all the rest of the matching 
     if len(text) < 3 or text not in string: 
      continue 

     if found and cls._is_processed(text, processed): 
      continue 

     # match the search word with accent, for any case 
     # ensure this is not part of a word by including 
     # two 'non-letter' character on both ends of the word 
     pattern = re.compile(ur'([^\w]|^)(%s)([^\w]|$)' % text, 
          re.UNICODE|re.IGNORECASE) 

     if re.search(pattern, string): 
      found += 1 

      # create the link string 
      # replace the word in the description 
      # use back references (\1, \2, etc) to preserve the original 
      # formatin 
      # use raw unicode strings (ur"string" notation) to avoid 
      # problems with accents and escaping 

      query = '-'.join(term.text.split()) 
      url = ur'{%% url namespace:static-search "%s" %%}' % query 
      replace_with = ur'\1<a title="\2 video streaming" href="%s">\2</a>\3' % url 

      string = re.sub(pattern, replace_with, string) 

      processed.add(text) 

      if found >= 3: 
       break 

    return string 

आप करेंगे शायद इस कोड के साथ-साथ हैं:

class SearchedTerm(models.Model): 

[...] 

@classmethod 
def _is_processed(cls, text, processed): 
    """ 
     Check if the text if part of the already processed string 
     we don't use `in` the set, but `in ` each strings of the set 
     to avoid subtring matching that will destroy the tags. 

     This is mainly an utility function so you probably won't use 
     it directly. 
    """ 
    if text in processed: 
     return True 

    return any(((text in string) for string in processed)) 

मैं वास्तव में संदर्भ के साथ केवल दो वस्तुओं है यह यहां संदिग्ध हो सकता है: terms और processed। लेकिन मैं उनके लिए एकत्रित कचरा नहीं होने का कोई कारण नहीं देख सकता।

संपादित करें:

मैं मैं कहना चाहिए कि इस विधि एक Django मॉडल विधि के अंदर ही कहा जाता है लगता है। मैं अगर यह प्रासंगिक है पता नहीं, लेकिन यहाँ कोड है:

class Video(models.Model): 

[...] 

def update_html_description(self, links=3, queryset=None): 
    """ 
     Take a list of all researched terms and search them in the 
     description. If they exist, turn them into links to the search 
     engine. Put the reset into `html_description`. 

     This use `add_search_link_to_text` and has therefor, the same 
     limitations. 

     It DOESN'T call save(). 
    """ 
    queryset = queryset or SearchedTerm.objects.filter(sites__in=self.sites.all()) 
    text = self.description or self.title 
    self.html_description = SearchedTerm.add_search_links_to_text(text, 
                    links, 
                    queryset) 

मैं कल्पना कर सकते हैं कि स्वत: अजगर regex कैशिंग कुछ स्मृति को खाता है। लेकिन इसे केवल एक बार करना चाहिए और update_html_description की प्रत्येक कॉल पर स्मृति खपत बढ़ जाती है।

समस्या यह नहीं है कि यह बहुत सारी स्मृति का उपभोग करता है, समस्या यह है कि यह इसे जारी नहीं करता है: प्रत्येक कॉल में राम का लगभग 3% हिस्सा होता है, अंत में इसे भरना और स्क्रिप्ट को क्रैश करना 'स्मृति आवंटित नहीं कर सकता '।

+2

' 'पाइथन जैसी कचरा एकत्रित भाषा में स्मृति को लेना लगभग असंभव है। कड़ाई से बोलते हुए, एक स्मृति रिसाव स्मृति है जिसमें इसका कोई संदर्भ नहीं है। सी ++ में यदि आप कक्षा में स्मृति आवंटित करते हैं, लेकिन विनाशक घोषित न करें, तो आपके पास स्मृति रिसाव हो सकती है। आपके पास यहां केवल उच्च मेमोरी खपत है। ' –

+0

:-) ठीक है। तब मुझे एक उच्च स्मृति खपत मिली जो प्रत्येक कॉल के बाद उच्च और उच्च हो जाती है। लेकिन चूंकि यह एक विधि है। और चूंकि मैं इसे पूरा करने के बाद किसी भी चीज को प्रतिबिंबित नहीं करता हूं, फिर भी कुछ स्मृति का उपभोग क्यों करता है? –

+0

इस बारे में प्रश्न अपडेट किया गया। –

उत्तर

3

एक बार जब आप इसे कॉल करते हैं तो संपूर्ण क्वेरीसेट स्मृति में लोड हो जाती है, यही आपकी याददाश्त को खाएगी। यदि परिणाम बड़े होते हैं तो आप परिणाम के हिस्सों को प्राप्त करना चाहते हैं, यह डेटाबेस पर अधिक हिट हो सकता है लेकिन इसका मतलब बहुत कम स्मृति खपत होगा।

+0

मैं ठीक हूँ पूरी क्वेरीसेट स्मृति में है। यह बहुत अधिक नहीं है: 100000 स्ट्रिंग अधिकतम मॉडल ऑब्जेक्ट में लपेटा गया है। प्रत्येक कॉल के बाद, इसे कचरा इकट्ठा किया जाना चाहिए। समस्या यह है कि प्रत्येक कॉल क्यूमेटिवली मेमोरी खाती है। पहली कॉल रैम का 3% लेती है अगला कॉल 6% और आगे। –

+0

इस बारे में प्रश्न अपडेट किया गया। –

1

सुनिश्चित करें कि आप DEBUG में नहीं चल रहे हैं।

+2

:-) यह एक प्रोड सर्वर है और DEBUG गलत पर सेट है। लेकिन अच्छी पकड़, यह वास्तव में स्मृति रिसाव का कारण बनती है और मैंने आपके जवाब को मुझे जांचने के लिए मजबूर किया। –

-1

मुझे लगता है कि मुझे यह कहना चाहिए कि इस विधि को Django मॉडल विधि के अंदर ही कहा जाता है।

क्यों @classmethod? यह "वर्ग स्तर"

इन सामान्य तरीकों के सामान्य नियमों के नियम क्यों नहीं हो सकते हैं - - सामान्य पाठ्यक्रमों में - कचरा इकट्ठा क्यों किया जाता है?

दूसरे शब्दों में

(एक जवाब के रूप में) @classmethod से छुटकारा।

+0

^^ @classmethod एक क्लास विधि के लिए है, जिसे update_html_description (self, links = 3, queryset = none) में कहा जाता है जो एक उदाहरण विधि है। यहां कोई भ्रम नहीं है। –

+0

@ ई-सैटिस। मुझे यकीन है कि कोई भ्रम नहीं है। कोई * आवश्यकता * भी है। –

+0

मैंने उन वर्गों का नाम जोड़ा जो वे चीजों को स्पष्ट करने के लिए हैं: SearchedTerm में एक क्लास विधि है जो किसी भी पाठ को जोड़ती है, जबकि वीडियो उदाहरण इसका उपयोग HTML_description को उतारने के लिए करते हैं। कारण add_search_links_to_text एक क्लास विधि है निश्चित रूप से यह एक उपयोगिता विधियों है, सर्च किए गए उदाहरणों पर कार्य करने के लिए कोई मतलब नहीं है। –

1

मैं समस्या का कारण खोजने में पूरी तरह से असमर्थ था, लेकिन अभी के लिए मैं एक स्क्रिप्ट को कॉल करके कुख्यात स्निपेट को अलग करके इसे पास कर रहा हूं (subprocess का उपयोग करके) जिसमें यह विधि कॉल शामिल है। स्मृति बढ़ जाती है लेकिन निश्चित रूप से, अजगर की प्रक्रिया मरने के बाद सामान्य हो जाती है।

गंदा के बारे में बात करें।

लेकिन यह सब मुझे अभी मिला है।

संबंधित मुद्दे