क्या पाइथन एक वैरिएबल का अनुकूलन करता है जो केवल रिटर्न वैल्यू के रूप में उपयोग किया जाता है?


106

निम्नलिखित दो कोड स्निपेट के बीच कोई अंतिम अंतर है? पहला किसी फ़ंक्शन में एक वैरिएबल के लिए एक मान प्रदान करता है और फिर उस वैरिएबल को लौटाता है। दूसरा फ़ंक्शन सीधे मान लौटाता है।

क्या पायथन उन्हें बराबर बाइटकोड में बदल देता है? क्या उनमें से एक तेज है?

केस 1 :

def func():
    a = 42
    return a

केस 2 :

def func():
    return 42

5
यदि आप dis.dis(..)दोनों का उपयोग करते हैं तो आप देखते हैं कि अंतर है , इसलिए हाँ। लेकिन अधिकांश वास्तविक दुनिया के अनुप्रयोगों में फ़ंक्शन के प्रसंस्करण की देरी की तुलना में इसका ओवरहेड इतना अधिक नहीं है।
विल्म वान ओन्सेम

4
दो संभावनाएँ हैं: (ए) आप इस कार्य को एक तंग लूप में कई (यानी कम से कम एक लाख) बार करने जा रहे हैं। उस स्थिति में आपको पायथन फ़ंक्शन को कॉल नहीं करना चाहिए, बल्कि इसके बजाय अपने लूप को सुपीरियर लाइब्रेरी जैसी किसी चीज़ का उपयोग करके सदिश करना चाहिए। (b) आप इस फ़ंक्शन को कई बार कॉल नहीं करने वाले हैं। उस मामले में इन फ़ंक्शन के बीच गति के अंतर के बारे में चिंता करने लायक होने के लिए बहुत कम है।
आर्थर टाका

जवाबों:


138

नहीं, यह नहीं है

CPython बाइट कोड का संकलन केवल एक छोटे से पीपहोल ऑप्टिमाइज़र के माध्यम से पारित किया जाता है जिसे केवल मूल अनुकूलन करने के लिए डिज़ाइन किया गया है ( इन अनुकूलन पर अधिक के लिए परीक्षण सूट में test_peepholer.py देखें )।

वास्तव में क्या होने जा रहा है, इस पर एक नज़र डालने के लिए, disउत्पन्न निर्देशों को देखने के लिए * का उपयोग करें । पहले फ़ंक्शन के लिए, असाइनमेंट युक्त:

from dis import dis
dis(func)
  2           0 LOAD_CONST               1 (42)
              2 STORE_FAST               0 (a)

  3           4 LOAD_FAST                0 (a)
              6 RETURN_VALUE

जबकि, दूसरे समारोह के लिए:

dis(func2)
  2           0 LOAD_CONST               1 (42)
              2 RETURN_VALUE

पहले में दो और (तेज़) निर्देशों का उपयोग किया जाता है: STORE_FASTऔर LOAD_FAST। ये fastlocalsवर्तमान निष्पादन फ्रेम की सरणी में एक त्वरित स्टोर और मूल्य को हड़प लेते हैं । फिर, दोनों मामलों में, एक RETURN_VALUEप्रदर्शन किया जाता है। इसलिए, दूसरे को निष्पादित करने के लिए आवश्यक कम आदेशों के कारण कभी-कभी थोड़ा तेज होता है।

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

अंत में, आपको इस तरह के छोटे मुद्दों के साथ खुद को परेशान नहीं करना चाहिए। गति में लाभ छोटे, निरंतर और, इस तथ्य से शुरू किए गए ओवरहेड द्वारा बौना है कि पायथन की व्याख्या की गई है।

* disएक छोटा पायथन मॉड्यूल है जो आपके कोड को असम्बद्ध करता है, आप इसका उपयोग पायथन बाइटकोड को देखने के लिए कर सकते हैं जिसे वीएम निष्पादित करेगा।

नोट: जैसा कि @Jorn Vernee द्वारा एक टिप्पणी में कहा गया है, यह पायथन के CPython कार्यान्वयन के लिए विशिष्ट है। यदि वे चाहें तो अन्य कार्यान्वयन अधिक आक्रामक अनुकूलन कर सकते हैं, सीपीथॉन नहीं करता है।


11
एक अजगर व्यक्ति (सी ++) नहीं है, इसलिए मुझे नहीं पता कि यह हुड के नीचे कैसे काम करता है लेकिन क्या पहले मामले को दूसरे मामले में अनुकूलित नहीं किया जाना चाहिए? एक सभ्य C ++ कंपाइलर उस अनुकूलन को बनाएगा।
नाथनऑलिवर

7
@NathanOliver यह वास्तव में नहीं करता है, पायथन यहाँ के रूप में यहाँ तक कि इसे स्मार्ट खेलने का प्रयास किए बिना बताया जाएगा।
दिमित्री फासरकिस हिलियार्ड

80
तथ्य यह है कि इस सवाल के जवाब में @ NathanOliver का पूरी तरह से उचित और बुद्धिमानी का अनुमान पूरी तरह से गलत है, मेरी नज़र में, इस बात का सबूत है कि यह "आत्म-व्याख्यात्मक", "बकवास", "बेवकूफ" प्रश्न नहीं है जिसका उत्तर दिया जा सकता है "एक पल सोचने के लिए" के रूप में, TigerhawkT3 हमें विश्वास होगा। यह वर्षों से एक पेशेवर, पायथन प्रोग्रामर होने के बावजूद एक मान्य, दिलचस्प सवाल है, जिसका जवाब मुझे नहीं मिला।
मार्क ऐमी

पायथन का कंपाइलर सर्वश्रेष्ठ 'रूढ़िवादी' है, 'बहुत रूढ़िवादी' नहीं। मुख्य डिजाइन लक्ष्य "जितना संभव हो उतना तेज होना नहीं है ... इसलिए आपको यह भी ध्यान नहीं है कि एक संकलन चरण मौजूद है।" यह "इसे सरल रखने के बाद" गौण है। "1 << (2 ** 34)" और "b'x '* (2 ** 32)" जैसे बड़े स्थिरांक वाले एक फ़ंक्शन को संकलन करने में कई सेकंड लगते हैं, और भले ही फ़ंक्शन कभी न हो। Daud। बड़े स्ट्रिंग को कंपाइलर द्वारा भी छोड़ दिया जाएगा। इन मामलों के लिए प्रस्तावित सुधारों को अस्वीकार कर दिया गया है क्योंकि वे संकलक को बहुत जटिल बना देंगे।
एंड्रयू डलके

इस पर अंदरूनी सूत्रों की टिप्पणी के लिए @AndrewDalke धन्यवाद, मैंने आपके द्वारा बताए गए मुद्दों को संबोधित करने के लिए शब्दों को बदल दिया।
दिमित्रिस फासारकिस हिलियार्ड

3

दोनों मूल रूप से एक ही हैं सिवाय इसके कि पहले मामले में वस्तु 42बस नामांकित चर के लिए तैयार की जाती है aया, दूसरे शब्दों में, नाम (यानी a) मूल्यों को संदर्भित करते हैं (यानी 42)। यह तकनीकी रूप से कोई असाइनमेंट नहीं करता है, इस अर्थ में कि यह कभी भी किसी डेटा की प्रतिलिपि नहीं बनाता है।

जबकि returning, इस नाम बाध्यकारी aपहले मामले में दिया जाता है, जबकि वस्तु 42दूसरे मामले में वापसी है।

अधिक पढ़ने के लिए, नेड बैचेल्ड द्वारा इस महान लेख को देखें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.