2011-06-08 5 views
6

मैं एक जनरेटर समारोह के प्रदर्शन को समझने के लिए कोशिश कर रहा हूँ। मैंने प्रोफाइलिंग डेटा एकत्र करने और निरीक्षण करने के लिए cProfile और pstats मॉड्यूल का उपयोग किया है। सवाल में समारोह यह है:जेनरेटर समारोह प्रदर्शन

def __iter__(self): 
    delimiter = None 
    inData  = self.inData 
    lenData = len(inData) 
    cursor  = 0 
    while cursor < lenData: 
     if delimiter: 
      mo = self.stringEnd[delimiter].search(inData[cursor:]) 
     else: 
      mo = self.patt.match(inData[cursor:]) 
     if mo: 
      mo_lastgroup = mo.lastgroup 
      mstart  = cursor 
      mend   = mo.end() 
      cursor  += mend 
      delimiter = (yield (mo_lastgroup, mo.group(mo_lastgroup), mstart, mend)) 
     else: 
      raise SyntaxError("Unable to tokenize text starting with: \"%s\"" % inData[cursor:cursor+200]) 

self.inData एक यूनिकोड पाठ स्ट्रिंग है, self.stringEnd 4 सरल regex के साथ एक dict है, self.patt एक बड़ा regex है। पूरी बात यह है कि बड़ी स्ट्रिंग को छोटे तारों में विभाजित करना है, एक-एक-एक।

एक कार्यक्रम में यह मैंने पाया कि कार्यक्रम की दौड़ समय का सबसे बड़ा हिस्सा इस समारोह में खर्च किया जाता है का उपयोग करता है रूपरेखा:

In [800]: st.print_stats("Scanner.py:124") 

     463263 function calls (448688 primitive calls) in 13.091 CPU seconds 

    Ordered by: cumulative time 
    List reduced from 231 to 1 due to restriction <'Scanner.py:124'> 

    ncalls tottime percall cumtime percall filename:lineno(function) 
    10835 11.465 0.001 11.534 0.001 Scanner.py:124(__iter__) 

लेकिन समारोह में ही की प्रोफ़ाइल देख रहे हैं, वहाँ काफी समय बिताया नहीं है

In [799]: st.print_callees("Scanner.py:124") 
    Ordered by: cumulative time 
    List reduced from 231 to 1 due to restriction <'Scanner.py:124'> 

Function     called... 
           ncalls tottime cumtime 
Scanner.py:124(__iter__) -> 10834 0.006 0.006 {built-in method end} 
           10834 0.009 0.009 {built-in method group} 
           8028 0.030 0.030 {built-in method match} 
           2806 0.025 0.025 {built-in method search} 
            1 0.000 0.000 {len} 

समारोह के बाकी बहुत अलावा, जबकि, कार्य नहीं है और अगर-बाकी: कार्यों के उप कॉल में। यहां तक ​​कि जनरेटर जो मैं उपयोग पर send विधि तेज है:

ncalls tottime percall cumtime percall filename:lineno(function) 
13643/10835 0.007 0.000 11.552 0.001 {method 'send' of 'generator' objects} 

क्या यह संभव है कि yield, एक मूल्य के उपभोक्ता को वापस गुजर, समय के बहुमत ले जा रहा है ?! और कुछ और जो मुझे पता नहीं है?

संपादित:

मैं शायद जनरेटर समारोह __iter__ एक छोटा सा वर्ग की एक विधि है कि उल्लेख किया जाना चाहिए था, इसलिए self इस वर्ग का एक उदाहरण को दर्शाता है।

+3

कितना बड़ा inData है? इसे बार-बार स्लाइड करना बहुत कुशल नहीं हो सकता है। हो सकता है कि आपने इसके बजाय itertools में islice का उपयोग करने का प्रयास किया हो। देखें कि इससे कोई फर्क पड़ता है या नहीं। – Dunes

+0

@ ड्यून्स धन्यवाद, कोशिश करेंगे। प्रदर्शन डेटा लगभग 1 एमबी की एक स्ट्रिंग पर लिया गया था। - यदि आप इसे एक उत्तर में डालते हैं, तो मैं इसे ऊपर उठा सकता हूं। – ThomasH

+0

क्या आपने [यह] कोशिश की है (http://stackoverflow.com/questions/4295799/how-to-improve-performance-of-this-code/4299378#4299378)? –

उत्तर

2

यह वास्तव में Dunes का उत्तर है, दुर्भाग्य से इसे केवल एक टिप्पणी के रूप में दिया गया है और ऐसा लगता है कि इसे उचित उत्तर में डालने की इच्छा नहीं है।

मुख्य प्रदर्शन अपराधी स्ट्रिंग स्लाइस थे। कुछ समय माप से पता चला है कि स्लाइसिंग प्रदर्शन बड़े स्लाइस के साथ अनुमानित रूप से घटता है (जिसका अर्थ है कि पहले से ही बड़ी स्ट्रिंग से बड़ा टुकड़ा लेना)। हल करने के लिए है कि अब मैं regex वस्तु तरीकों के लिए pos पैरामीटर का उपयोग:

if delimiter: 
     mo = self.stringEnd[delimiter].search(inData, pos=cursor) 
    else: 
     mo = self.patt.match(inData, pos=cursor) 

all जो मदद के लिए धन्यवाद।

+1

आह, क्षमा करें। मैं पिछले कुछ दिनों में काम पर बहुत व्यस्त था। मैंने केवल समस्या का पता लगाया, क्योंकि मेरा समाधान पर्याप्त नहीं था। तो समाधान खोजने के लिए आपको श्रेय। – Dunes

+0

@ ड्यून्स मैं समस्या के लिए पूछ रहा था, इसलिए आपकी टिप्पणी काफी पर्याप्त थी। अगली बार :-) । – ThomasH

1

सही ढंग से अपने नमूना पढ़ने, आप एक जनरेटर वस्तु ले जा रहे हैं यह delimiter में डाल, और एक सरणी देखने के लिए उपयोग। यह आपकी गति समस्या नहीं हो सकती है, लेकिन मुझे पूरा यकीन है कि यह एक बग है।

+1

यदि आप 'delimiter = (उपज ...) 'भाग का संदर्भ लें, नहीं। यह फ़ंक्शन ** ** कोरआउट ** है, जो उपयोगकर्ता को 'co.send (x) 'करने की अनुमति देता है, जो निष्पादन को फिर से शुरू करता है (जैसे' अगला (जनरेटर)') और '(उपज ...)' ' एक्स' (यदि आप इसे एक पुनरावर्तनीय के रूप में उपयोग करते हैं, तो यह 'कोई नहीं' आईआईआरसी का मूल्यांकन करता है)। – delnan

+0

हां, जैसा कि डेलन ने लिखा था, मैं कभी-कभी जनरेटर के लिए छोटे स्ट्रिंग में गुजर रहा हूं (बाहरी से .send का उपयोग करके), इसे अगले खंड के लिए एक अलग रेगेक्स का उपयोग करने के लिए स्विच करने के लिए। – ThomasH

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