दिलचस्प पोस्ट
jQuery का .बिंद () बनाम .on () Array.prototype और Object.prototype पर जावास्क्रिप्ट में विधि को परिभाषित करने के लिए कैसे करें ताकि यह लूप में दिखाई न दें मूल्यों की सूची के खिलाफ चर समानता की जांच करें यूके पोस्टकोड रेगेक्स (व्यापक) intl एक्सटेंशन: स्थापित php_intl.dll in_array () और बहुआयामी सरणी Django: मैं पोस्ट डेटा पर एक पोस्ट पुनर्निर्देशित कैसे कर सकता हूं? जीआईटी रिपॉजिटरी का पुनरावृत्ति विफल किसी VARCHAR फ़ील्ड में स्ट्रिंग की घटनाओं की संख्या की गणना करें? String.Empty और "" (रिक्त स्ट्रिंग) के बीच अंतर क्या है? विंडोज फॉर्म के लिए यूआई डिज़ाइन पैटर्न (जैसे एमपीवीएम के लिए एमवीवीएम) C ++ में एप्लिकेशन के साथ फ़ाइल एक्सटेंशन को संबद्ध करने के लिए रजिस्ट्री प्रविष्टि बनाएं मैं एक ही पृष्ठ पर jQuery के विभिन्न संस्करणों को कैसे चलाऊं? मैं कैसे विशेष वर्णों के साथ सौदा करूँगा \ ^ $।? * * | + () [[मेरे रेगेक्स में? अजाक्स का उपयोग करके पीडीएफ फाईल को डाउनलोड और खोलें

पायथन कोड फ़ंक्शन में तेजी से क्यों चलता है?

def main(): for i in xrange(10**8): pass main() 

पायथन में कोड का यह टुकड़ा चल रहा है (नोट: लिनक्स में समय बीएसएएच में समय फ़ंक्शन के साथ किया जाता है।)

 real 0m1.841s user 0m1.828s sys 0m0.012s 

हालांकि, यदि फ़ंक्शन के लिए लूप नहीं रखा गया है,

 for i in xrange(10**8): pass 

तो यह एक बहुत अधिक समय के लिए चलाता है:

 real 0m4.543s user 0m4.524s sys 0m0.012s 

ऐसा क्यों है?

वेब के समाधान से एकत्रित समाधान "पायथन कोड फ़ंक्शन में तेजी से क्यों चलता है?"

आप पूछ सकते हैं कि विश्व स्तर की तुलना में स्थानीय चर को स्टोर करने में तेज़ी क्यों बढ़ रही है यह एक CPththon कार्यान्वयन विवरण है।

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

एक वैश्विक लुकअप ( LOAD_GLOBAL ) के लिए इसके विपरीत है, जो एक हैश और इतने पर शामिल एक सच्चे LOAD_GLOBAL खोज है। संयोग से, यही कारण है कि आपको global i को निर्दिष्ट करना होगा यदि आप चाहते हैं कि यह वैश्विक हो: यदि आप कभी भी एक गुंजाइश के अंदर एक चर को आवंटित करते हैं, तो कंपाइलर STORE_FAST को अपनी पहुंच के लिए जारी करेगा जब तक कि आप इसे न बताएं।

वैसे, वैश्विक लुकअप अभी भी बहुत अनुकूल हैं। विशेषता लुकअप foo.bar वास्तव में धीमी हैं!

यहां स्थानीय चर दक्षता पर छोटा चित्रण है ।

फ़ंक्शन के अंदर, बाइटकोड है

  2 0 SETUP_LOOP 20 (to 23) 3 LOAD_GLOBAL 0 (xrange) 6 LOAD_CONST 3 (100000000) 9 CALL_FUNCTION 1 12 GET_ITER >> 13 FOR_ITER 6 (to 22) 16 STORE_FAST 0 (i) 3 19 JUMP_ABSOLUTE 13 >> 22 POP_BLOCK >> 23 LOAD_CONST 0 (None) 26 RETURN_VALUE 

शीर्ष स्तर पर, बाइटकोड है

  1 0 SETUP_LOOP 20 (to 23) 3 LOAD_NAME 0 (xrange) 6 LOAD_CONST 3 (100000000) 9 CALL_FUNCTION 1 12 GET_ITER >> 13 FOR_ITER 6 (to 22) 16 STORE_NAME 1 (i) 2 19 JUMP_ABSOLUTE 13 >> 22 POP_BLOCK >> 23 LOAD_CONST 2 (None) 26 RETURN_VALUE 

अंतर यही है कि STORE_FAST STORE_NAME तुलना में तेज (!) है ऐसा इसलिए है क्योंकि किसी फ़ंक्शन में, i एक स्थानीय i , लेकिन यह एक वैश्विक स्तर पर है, यह एक वैश्विक है।

बायटेक की जांच करने के लिए, dis मॉड्यूल का उपयोग करें। मैं फ़ंक्शन को सीधे से अलग करने में सक्षम था, लेकिन ऊपरी कोड को अलग करने के लिए मुझे compile बिल्टिन का उपयोग करना था

लोकल / ग्लोबल वैरिएबल स्टोर टाइम्स के अलावा, opcode prediction फ़ंक्शन को तेज़ बनाता है

जैसा कि अन्य जवाबों की व्याख्या करते हैं, फ़ंक्शन, लूप में STORE_FAST opcode का उपयोग करता है। फ़ंक्शन के लूप के लिए यहां बाइटकोड है:

  >> 13 FOR_ITER 6 (to 22) # get next value from iterator 16 STORE_FAST 0 (x) # set local variable 19 JUMP_ABSOLUTE 13 # back to FOR_ITER 

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

इस मामले में, हर बार पायथन FOR_ITER (लूप का शीर्ष) देखता है, यह "अनुमान लगाता है" कि STORE_FAST इसे निष्पादित करने वाला अगला STORE_FAST है। अजगर फिर अगले opcode पर STORE_FAST और, अगर भविष्यवाणी सही थी, यह सीधे STORE_FAST कूदता है। इसमें दो opcodes को एक एकल opcode में फैलाने का प्रभाव है।

दूसरी ओर, STORE_NAME opcode वैश्विक स्तर पर लूप में उपयोग किया जाता है। जब यह opcode देखता है तो अजगर समान भविष्यवाणियां नहीं करता है इसके बजाय, यह मूल्यांकन-लूप के शीर्ष पर वापस जाना चाहिए जो उस गति के स्पष्ट निहितार्थ हैं जिस पर लूप निष्पादित होता है।

इस अनुकूलन के बारे में कुछ अधिक तकनीकी जानकारी देने के लिए, यहां पर ceval.c फ़ाइल ("पायथन की वर्चुअल मशीन का इंजन") से एक उद्धरण है:

कुछ एपोडोड जोड़े में आते हैं, इसलिए यह पहली बार चलाने के दूसरे कोड की भविष्यवाणी करना संभव है। उदाहरण के लिए, GET_ITER अक्सर FOR_ITER द्वारा FOR_ITER किया जाता है और FOR_ITER अक्सर STORE_FAST या UNPACK_SEQUENCE द्वारा पीछा किया जाता है

भविष्यवाणी की पुष्टि करने से एक निरंतर के खिलाफ एक रजिस्टर चर के एक उच्च गति परीक्षण की लागत होती है। अगर युग्मन अच्छा था, तो प्रोसेसर की अपनी आंतरिक शाखा की भविष्यवाणी में सफलता की एक उच्च संभावना है, जिसके परिणामस्वरूप अगले ओपरोड पर शून्य-ओवरहेड संक्रमण हो सकता है। एक सफल पूर्वानुमान अपने दो अप्रत्याशित शाखाओं, HAS_ARG परीक्षण और स्विच-केस सहित eval-loop के माध्यम से एक यात्रा को बचाता है। प्रोसेसर की आंतरिक शाखा की भविष्यवाणी के साथ संयुक्त, एक सफल PREDICT में दो ऑप्कोड्स चलाने के प्रभाव का प्रभाव होता है, जैसे कि वे एक-दूसरे से मिलकर शरीर को एक नया ऑपोड करते हैं

हम FOR_ITER opcode के स्रोत कोड में बिल्कुल देख सकते हैं जहां STORE_FAST लिए पूर्वानुमान दिया गया है:

 case FOR_ITER: // the FOR_ITER opcode case v = TOP(); x = (*v->ob_type->tp_iternext)(v); // x is the next value from iterator if (x != NULL) { PUSH(x); // put x on top of the stack PREDICT(STORE_FAST); // predict STORE_FAST will follow - success! PREDICT(UNPACK_SEQUENCE); // this and everything below is skipped continue; } // error-checking and more code for when the iterator ends normally 

if (*next_instr == op) goto PRED_##op फ़ंक्शन का विस्तार होता है if (*next_instr == op) goto PRED_##op अर्थात् हम सिर्फ अनुमानित opcode की शुरुआत करने के लिए कूदते हैं इस मामले में, हम यहाँ कूदते हैं:

 PREDICTED_WITH_ARG(STORE_FAST); case STORE_FAST: v = POP(); // pop x back off the stack SETLOCAL(oparg, v); // set it as the new local variable goto fast_next_opcode; 

स्थानीय वेरिएबल अब सेट किया गया है और अगली ओपेकोड निष्पादन के लिए तैयार है। जब तक यह अंत तक नहीं पहुंच पाता, तब तक अजगर सफल रहता है, जिससे हर बार सफल भविष्यवाणी की जा सकती है।

पायथन विकी पृष्ठ में अधिक जानकारी है कि CPython की वर्चुअल मशीन कैसे काम करती है।