2012-12-07 21 views
12

PEP 412, पायथन 3.3 में लागू, विशेषता शब्दकोशों में बेहतर संचालन प्रस्तुत करता है, जो क्लास इंस्टेंस के मेमोरी पदचिह्न को प्रभावी ढंग से कम करता है। __slots__ उसी उद्देश्य के लिए डिज़ाइन किया गया था, तो क्या __slots__ का उपयोग करने में कोई बात नहीं है?क्या पीईपी 412 __slots__ अनावश्यक बनाता है?

जवाब अपने आप को, मैं निम्नलिखित परीक्षण चलाने पता लगाने के लिए की कोशिश में, लेकिन परिणाम बहुत मतलब नहीं है:

class Slots(object): 
    __slots__ = ['a', 'b', 'c', 'd', 'e'] 
    def __init__(self): 
     self.a = 1 
     self.b = 1 
     self.c = 1 
     self.d = 1 
     self.e = 1 

class NoSlots(object): 
    def __init__(self): 
     self.a = 1 
     self.b = 1 
     self.c = 1 
     self.d = 1 
     self.e = 1 

अजगर 3.3 परिणाम:

>>> sys.getsizeof([Slots() for i in range(1000)]) 
Out[1]: 9024 
>>> sys.getsizeof([NoSlots() for i in range(1000)]) 
Out[1]: 9024 

अजगर 2.7 परिणाम:

>>> sys.getsizeof([Slots() for i in range(1000)]) 
Out[1]: 4516 
>>> sys.getsizeof([NoSlots() for i in range(1000)]) 
Out[1]: 4516 

मैं आकार अजगर 2.7 के लिए कम से कम अलग करने के लिए है, इसलिए उम्मीद है | मैं वहाँ मैं मान परीक्षण के साथ कुछ गलत है।

+0

क्या आपने अभी तक वास्तविक दुनिया की स्थितियों में अंतर को माप लिया है? :-) इसके अलावा, '__slots__' (एबी) इसके दुष्प्रभावों के लिए उपयोग किया जा सकता है, जैसे तथ्य यह है कि यह मनमाने ढंग से गुणों को जोड़ा जा रहा है। –

+0

हां, मैं __slots__ के साथ समस्या से अवगत हूं, यह एक विशिष्ट उपयोग मामले से संबंधित एक अकादमिक प्रश्न था। मैंने कुछ परीक्षण चलाने की कोशिश की, लेकिन पाइथन 3.3 या 2.7 में स्लॉट्स का उपयोग करने के बीच कोई अंतर नहीं मिला। लेकिन शायद मेरा परीक्षण दोषपूर्ण है, इसलिए मैं इसे भी पोस्ट करूंगा। – aquavitae

उत्तर

4

नहीं, पीईपी 412 __slots__ अनावश्यक बनाते हैं।


पहला, आर्मीन रिगो सही है कि आप इसे ठीक से माप नहीं रहे हैं। आपको मापने की आवश्यकता है वस्तु का आकार, साथ ही मूल्य, साथ ही __dict__ स्वयं (केवल NoSlots के लिए) और कुंजी (केवल NoSlots के लिए)।

या आप वह क्या पता चलता है कर सकता है:

cls = Slots if len(sys.argv) > 1 else NoSlots 
def f(): 
    tracemalloc.start() 
    objs = [cls() for _ in range(100000)] 
    print(tracemalloc.get_traced_memory()) 
f() 

जब मैं ओएस एक्स पर 64-बिट पर इस चलाने CPython 3.4, मैं 8824968NoSlots और 25624872Slots के लिए के लिए मिलता है। तो, ऐसा लगता है कि NoSlots उदाहरण 88 बाइट्स लेता है, जबकि Slots उदाहरण 256 बाइट्स लेता है।


यह कैसे संभव है?

क्योंकि __slots__ और एक कुंजी-विभाजन __dict__ के बीच अभी भी दो अंतर हैं।

सबसे पहले, शब्दकोशों द्वारा उपयोग की गई हैश टेबल 2/3s से नीचे रखी जाती हैं, और वे तेजी से बढ़ती हैं और न्यूनतम आकार होती है, इसलिए आपके पास कुछ अतिरिक्त जगह होगी। और source पर अच्छी तरह से टिप्पणी करके देखकर कितना स्थान बनाना मुश्किल नहीं है: आपके पास 5 स्लॉट पॉइंटर्स की बजाय 8 हैश बाल्टी होगी।

दूसरा, शब्दकोश स्वयं ही मुफ़्त नहीं है; इसमें मानक ऑब्जेक्ट हेडर, एक गिनती और दो पॉइंटर्स हैं।यह बहुत कुछ नहीं लग सकता है, लेकिन जब आप किसी ऑब्जेक्ट के बारे में बात कर रहे हैं जिसमें केवल कुछ विशेषताओं को प्राप्त किया गया है (ध्यान दें कि अधिकतर ऑब्जेक्ट्स में केवल कुछ विशेषताएं हैं ...), हैडर हेडर हैश टेबल के रूप में बहुत अंतर कर सकता है ।

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


अंत में, सूचना है कि पीईपी 412 केवल दावा है:

बेंचमार्किंग पता चलता है कि स्मृति उपयोग वस्तु उन्मुख कार्यक्रमों

जहां के बारे में सोचो के लिए 20% तक 10% से कम हो जाता है __slots__ का उपयोग करें। या तो बचत इतनी बड़ी है कि __slots__ का उपयोग नहीं करना हास्यास्पद होगा, या आपको वास्तव में पिछले 15% को निचोड़ने की आवश्यकता है। या आप एक एबीसी या अन्य कक्षा का निर्माण कर रहे हैं जिसे आप कहां से जानते हैं कि सब-क्लास को बचत की आवश्यकता हो सकती है। किसी भी दर पर, उन मामलों में, तथ्य यह है कि आपको __slots__, या लाभ के दो तिहाई लाभ के बिना आधा लाभ मिलता है, अभी भी शायद ही कभी पर्याप्त होगा; आपको अभी भी __slots__ का उपयोग करने की आवश्यकता होगी।

वास्तविक जीत उन मामलों में है जहां __slots__ का उपयोग करने योग्य नहीं है; आपको मुफ्त में एक छोटा सा लाभ मिलेगा।

(इसके अलावा, निश्चित रूप से कुछ प्रोग्रामर हैं जो __slots__ से बाहर नरक का उपयोग करते हैं, और हो सकता है कि यह परिवर्तन उनमें से कुछ को कुछ ऊर्जा को अनुकूलित करने के लिए कुछ अन्य लोगों को अनुकूलित कर सके, यदि आप भाग्यशाली हैं, तो अप्रासंगिक नहीं है।)

+1

आपने 'नोस्लॉट्स' और 'स्लॉट्स' उदाहरणों के लिए मेमोरी आकार दिए हैं, लेकिन क्या आप ऑर्डर के बारे में सुनिश्चित हैं? 'स्लॉट्स' उदाहरण 'नोस्लॉट्स' की तुलना में हल्का नहीं होना चाहिए? पायथन 3.4 के साथ विन 7 64 बिट्स पर मैं यही प्राप्त करता हूं। –

5

समस्या sys.getsizeof() है, जो शायद ही कभी आप जो उम्मीद करते हैं वह लौटाती है। उदाहरण के लिए इस मामले में यह किसी ऑब्जेक्ट के "आकार" को __dict__ के आकार के हिसाब से गिना जाता है। मेरा सुझाव है कि आप 100'000 उदाहरण बनाने के वास्तविक स्मृति उपयोग को मापकर पुनः प्रयास करें।

ध्यान दें कि पायथन 3.3 व्यवहार PyPy द्वारा प्रेरित था, जिसमें __slots__ कोई फर्क नहीं पड़ता, इसलिए मुझे उम्मीद है कि यह पायथन 3.3 में भी कोई फर्क नहीं पड़ता। जहां तक ​​मैं कह सकता हूं, __slots__ अब लगभग किसी भी उपयोग का नहीं है।

+0

मैंने अभी 64-बिट पायथन 3.4 के साथ सुझाए गए परीक्षण को चलाया; 'tracemalloc' के अनुसार,' श्रेणी में (100000) के लिए 'स्लॉट्स()' '2424968' आवंटित करता है, जबकि 'नोस्लॉट्स' के साथ यह '25624872' है। यह सुनिश्चित करने के लिए [कोड] (http://pastebin.com/EF96k4na) देखें कि मैंने कुछ बेवकूफ नहीं किया है। – abarnert

+0

इसके अलावा, मैं नहीं देख सकता कि यह _no_ अंतर कैसे बना सकता है। हैश तालिका को केवल दो तिहाई लोड करने से ढीला है (जिसे मानों के लिए अप्रत्यक्ष अनुक्रमित सरणी का उपयोग करके तय किया जा सकता है, या पहली नई प्रतिलिपि देखी जाने पर हैश तालिका को कॉम्पैक्ट करके, या उनमें से कोई भी अन्य चाल नहीं है, लेकिन उनमें से कोई भी नहीं किया जा रहा है)। साथ ही, 'dict' हेडर स्वयं मुक्त नहीं है-यह केवल एक छोटा निरंतर ओवरहेड हो सकता है, लेकिन न्यूनतम आकार वाली तालिका और छोटे int '1' के 5 संदर्भों की तुलना में, यह ऑब्जेक्ट का सबसे बड़ा हिस्सा है। – abarnert

+0

मैंने सीपीथॉन 3.3 कार्यान्वयन पर विस्तार से नहीं देखा, इसलिए मैं आपको यह नहीं बता सकता कि यह अभी भी '__slots__' का उपयोग करने के लिए इतना बड़ा अंतर क्यों बनाता है। मैं बस इतना कह सकता हूं कि '__slots__' पीपीपीई (दोनों पीपीपी 2 और पीईपी 3) में सख्ती से कोई फर्क नहीं पड़ता है। –

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