2012-01-20 14 views
5

मैं एक कस्टम इटरेटर के साथ एक छोटे कंटेनर पर फिर से शुरू होने पर आश्चर्यजनक प्रदर्शन अंतर की तरह लग रहा हूं। मैं उम्मीद कर रहा था कि कोई मुझे यह समझने में सक्षम हो सकता है कि ये मतभेद कहां से आ रहे हैं।कस्टम इटरेटर प्रदर्शन

पहले कुछ संदर्भ; मैं बूस्ट :: पायथन का उपयोग करके कई पायथन एक्सटेंशन मॉड्यूल लिख रहा हूं, जिनमें से एक 3 डी फ्लोट वेक्टर प्रकार के लिए बाध्यकारी है जो getitem लागू करता है। चूंकि इसे इसके ऊपर फिर से शुरू करना संभव है, हालांकि यह काफी धीमा लगता है, लेकिन यह स्पष्ट नहीं है कि मैंने चीजों को कैसे काम करते हैं, इस बारे में बेहतर विचार पाने के लिए मैंने पाइथन में कुछ सरल कस्टम इटरेटर्स के साथ खेलने का फैसला किया। कौन सा है, जहां इन iterators से आया है ...

class MyIterator1(object): 
    __slots__ = ['values', 'popfn'] 

    def __init__(self): 
     self.values = ['x', 'y', 'z'] 
     self.popfn = self.values.pop 

    def __length_hint__(self): 
     return 3 

    def __iter__(self): 
     return self 

    def next(self): 
     try: 
      return self.popfn() 
     except IndexError: 
      raise StopIteration 

class MyIterator2(object): 
    __slots__ = ['values', 'itfn'] 

    def __init__(self): 
     self.values = ['x', 'y', 'z'] 
     it = iter(self.values) 
     self.itfn = it.next 

    def __length_hint__(self): 
     return 3 

    def __iter__(self): 
     return self 

    def next(self): 
     return self.itfn() 

class MyIterator3(object): 
    __slots__ = ['values', 'i'] 

    def __init__(self): 
     self.values = ['x', 'y', 'z'] 
     self.i = 0 

    def __length_hint__(self): 
     return 3 

    def __iter__(self): 
     return self 

    def next(self): 
     if self.i >= 3: 
      raise StopIteration 
     value = self.values[self.i] 
     self.i += 1 
     return value 

def MyIterator4(): 
    val = ['x', 'y', 'z'] 
    yield val[0] 
    yield val[1] 
    yield val[2] 

अगला मैं timeit मॉड्यूल के साथ एक स्क्रिप्ट (जो मान लिया गया है इसके बाद के संस्करण कोड एक मॉड्यूल कहा जाता testiter में है)

import timeit 

timer1 = timeit.Timer('r = list(testiter.MyIterator1())', 'import testiter') 
timer2 = timeit.Timer('r = list(testiter.MyIterator2())', 'import testiter') 
timer3 = timeit.Timer('r = list(testiter.MyIterator3())', 'import testiter') 
timer4 = timeit.Timer('r = list(testiter.MyIterator4())', 'import testiter') 
timer5 = timeit.Timer('r = list(iter(["x", "y", "z"]))', 'import testiter') 

print 'list(testiter.MyIterator1())' 
print timer1.timeit() 

print "\n" 

print 'list(testiter.MyIterator2())' 
print timer2.timeit() 

print "\n" 

print 'list(testiter.MyIterator3())' 
print timer3.timeit() 

print "\n" 

print 'list(testiter.MyIterator4())' 
print timer4.timeit() 

print "\n" 

print 'list(iter(["x", "y", "z"]))' 
print timer5.timeit() 

यह प्रिंट के माध्यम से इन भागा निम्नलिखित

list(testiter.MyIterator1()) 
8.5735929


list(testiter.MyIterator2()) 
5.28959393501 


list(testiter.MyIterator3()) 
6.11230111122 


list(testiter.MyIterator4()) 
2.31263613701 


list(iter(["x", "y", "z"])) 
1.26243281364 

अनजाने में पाइथन लिस्टिटरेटर काफी मार्जिन से सबसे तेज़ है। मुझे लगता है कि यह पाइथन के भीतर कुछ जादू अनुकूलन के लिए नीचे है। जनरेटर माईइटरेटर कक्षाओं की तुलना में काफी तेज़ है, जो कि मैं फिर से आश्चर्यचकित नहीं हूं, और मान लीजिए कि सी में किए गए सभी कामों के कारण, हालांकि यह अनुमान है। अब दूसरों को और अधिक भ्रमित/आश्चर्यजनक हैं। क्या वे इस संदर्भ में प्रतीत होते हैं या कथन को छोड़कर कोशिश कर रहे हैं या कुछ और चल रहा है?

इन मतभेदों को समझाने में कोई मदद की सराहना की जाएगी! लंबी पोस्ट के लिए माफ़ी।

+2

आप [x ',' y ',' z '] (जहां संभव हो) के बजाय tuple का उपयोग करने का प्रयास कर सकते हैं: tuple निर्माण सूची की तुलना में थोड़ा तेज़ है। –

उत्तर

2

मेरे सिर के ऊपर से कुछ विचार; खेद है अगर वे पर्याप्त स्पष्ट नहीं कर रहे हैं:

  • पहले इटरेटर सूची के popnext लागू करने के लिए उपयोग कर रहा है, जिसका अर्थ है सूची के बाद प्रत्येक तत्व लिया गया है उत्परिवर्तित है। शायद गतिशील रूप से आवंटित समग्र डेटा संरचना का यह उत्परिवर्तन प्रदर्शन को कम कर रहा है। सभी सूचियों के कार्यान्वयन विवरण पर निर्भर करता है, इसलिए यह पूरी तरह से अप्रासंगिक हो सकता है।
  • अंतिम पुनरावर्तक परिणाम उत्पन्न करने के लिए एक साधारण संदर्भ में भाषा (उपज) में वायर्ड सुविधा का उपयोग कर रहा है। एक अनुमान में, मैं कहूंगा कि यह इंगित करता है कि एक ही परिणाम प्राप्त करने का प्रयास करने वाले कस्टम इटरेटर वर्ग की तुलना में ऑप्टिमाइज़ेशन के लिए और अधिक जगह है।
  • 5 वें टाइमर कस्टम इटरेटर का उपयोग नहीं कर रहा है, और इसके बजाय सीधे सूचियों के लिए प्रदान किए गए एक का उपयोग कर रहा है। सूचियों के लिए इटरेटर शायद अच्छी तरह से अनुकूलित हैं, और ऐसे कस्टम वर्गों का संकेत नहीं है जो उन कस्टम वर्गों का उपयोग करते हैं, जिनमें से कुछ आंतरिक रूप से ऐसी सूची इटेटरेटर का उपयोग कर रहे हैं।
+1

मैं जोड़ता हूं कि अपवाद को उठाना और पकड़ना अपेक्षाकृत महंगा है: http://paltman.com/2008/01/18/try-except-performance-in-python-a-simple-test/। – Noah

+0

आह, ज़ाहिर है। मजेदार कैसे सचमुच स्पष्ट चीजें मुझे याद आती हैं =) मैंने कभी नहीं समझा कि क्यों पाइथन और रुबी सोचते हैं कि इस तरह की चीजों के लिए अपवादों का उपयोग क्यों किया जाना चाहिए ... – Louis

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