अजगर प्रोग्रामिंग भाषा आपको मल्टीप्रोसेसिंग या मल्टीथ्रेडिंग का उपयोग करने की अनुमति देती है। इस ट्यूटोरियल में, आप पायथन में मल्टीथ्रेडेड एप्लिकेशन लिखना सीखेंगे।
एक धागा क्या है?
एक धागा समवर्ती प्रोग्रामिंग पर परिच्छेदन की एक इकाई है। मल्टीथ्रेडिंग एक तकनीक है जो एक सीपीयू को एक ही समय में एक प्रक्रिया के कई कार्यों को निष्पादित करने की अनुमति देती है। ये सूत्र अपनी प्रक्रिया संसाधनों को साझा करते समय व्यक्तिगत रूप से निष्पादित कर सकते हैं।
एक प्रक्रिया क्या है?
एक प्रक्रिया मूल रूप से निष्पादन में कार्यक्रम है। जब आप अपने कंप्यूटर (जैसे ब्राउज़र या टेक्स्ट एडिटर) में कोई एप्लिकेशन शुरू करते हैं, तो ऑपरेटिंग सिस्टम एक प्रक्रिया बनाता है ।
पायथन में मल्टीथ्रेडिंग क्या है?
पायथन प्रोग्रामिंग में मल्टीथ्रेडिंग एक जानी-मानी तकनीक है जिसमें एक प्रक्रिया में कई सूत्र मुख्य थ्रेड के साथ अपने डेटा स्थान को साझा करते हैं जो थ्रेड के भीतर सूचना साझा करना और संचार को आसान और कुशल बनाता है। थ्रेड्स प्रक्रियाओं की तुलना में हल्के होते हैं। मल्टी थ्रेड्स अपनी प्रक्रिया संसाधनों को साझा करते समय व्यक्तिगत रूप से निष्पादित कर सकते हैं। मल्टीथ्रेडिंग का उद्देश्य एक ही समय में कई कार्यों और फ़ंक्शन कोशिकाओं को चलाना है।
मल्टीप्रोसेसिंग क्या है?
मल्टीप्रोसेसिंग आपको एक साथ कई असंबंधित प्रक्रियाओं को चलाने की अनुमति देता है। ये प्रक्रियाएं अपने संसाधनों को साझा नहीं करती हैं और आईपीसी के माध्यम से संवाद करती हैं।
पाइथन मल्टीथ्रेडिंग बनाम मल्टीप्रोसेसिंग
प्रक्रियाओं और थ्रेड्स को समझने के लिए, इस परिदृश्य पर विचार करें: आपके कंप्यूटर पर एक .exe फ़ाइल एक प्रोग्राम है। जब आप इसे खोलते हैं, तो ओएस इसे मेमोरी में लोड करता है, और सीपीयू इसे निष्पादित करता है। प्रोग्राम का उदाहरण जो अब चल रहा है उसे प्रक्रिया कहा जाता है।
हर प्रक्रिया में 2 मूलभूत घटक होंगे:
- कोड
- आंकड़ा
अब, एक प्रक्रिया में थ्रेड्स नामक एक या अधिक उप-भाग हो सकते हैं । यह OS आर्किटेक्चर पर निर्भर करता है। आप थ्रेड के बारे में सोच सकते हैं कि इस प्रक्रिया के एक भाग के रूप में जिसे ऑपरेटिंग सिस्टम द्वारा अलग से निष्पादित किया जा सकता है।
दूसरे शब्दों में, यह निर्देशों की एक धारा है जिसे ओएस द्वारा स्वतंत्र रूप से चलाया जा सकता है। एक ही प्रक्रिया के भीतर थ्रेड्स उस प्रक्रिया के डेटा को साझा करते हैं और समानता की सुविधा के लिए एक साथ काम करने के लिए डिज़ाइन किए गए हैं।
इस ट्यूटोरियल में आप सीखेंगे,
- एक धागा क्या है?
- एक प्रक्रिया क्या है?
- मल्टीथ्रेडिंग क्या है?
- मल्टीप्रोसेसिंग क्या है?
- पाइथन मल्टीथ्रेडिंग बनाम मल्टीप्रोसेसिंग
- मल्टीथ्रेडिंग का उपयोग क्यों करें?
- पायथन मल्टीट्रेडिंग
- थ्रेड और थ्रेडिंग मॉड्यूल
- धागा मॉड्यूल
- थ्रेडिंग मॉड्यूल
- गतिरोध और दौड़ की स्थिति
- धागे को सिंक्रोनाइज़ करना
- GIL क्या है?
- GIL की आवश्यकता क्यों थी?
मल्टीथ्रेडिंग का उपयोग क्यों करें?
मल्टीथ्रेडिंग आपको एक एप्लिकेशन को कई उप-कार्यों में तोड़ने और इन कार्यों को एक साथ चलाने की अनुमति देता है। यदि आप सही तरीके से मल्टीथ्रेडिंग का उपयोग करते हैं, तो आपके आवेदन की गति, प्रदर्शन और प्रतिपादन सभी में सुधार किया जा सकता है।
पायथन मल्टीट्रेडिंग
पायथन दोनों बहुसंकेतन के साथ-साथ मल्टीथ्रेडिंग के लिए निर्माण का समर्थन करता है। इस ट्यूटोरियल में, आप मुख्य रूप से अजगर के साथ मल्टीथ्रेडेड एप्लिकेशन को लागू करने पर ध्यान केंद्रित करेंगे । दो मुख्य मॉड्यूल हैं जिनका उपयोग पायथन में धागे को संभालने के लिए किया जा सकता है:
- धागा मॉड्यूल, और
- सूत्रण मॉड्यूल
हालांकि, अजगर में, एक वैश्विक इंटरप्रेटर लॉक (जीआईएल) भी कहा जाता है। यह बहुत अधिक प्रदर्शन हासिल करने की अनुमति नहीं देता है और यहां तक कि कुछ मल्टीथ्रेडेड अनुप्रयोगों के प्रदर्शन को कम कर सकता है । आप इस ट्यूटोरियल के आगामी अनुभागों में इसके बारे में जानेंगे।
थ्रेड और थ्रेडिंग मॉड्यूल
इस ट्यूटोरियल में आप जिन दो मॉड्यूल के बारे में जानेंगे, वे हैं थ्रेड मॉड्यूल और थ्रेडिंग मॉड्यूल ।
हालाँकि, थ्रेड मॉड्यूल लंबे समय से हटा दिया गया है। पायथन 3 के साथ शुरू, यह अप्रचलित के रूप में नामित किया गया है और केवल पिछड़े संगतता के लिए __thread के रूप में सुलभ है ।
आपको उन अनुप्रयोगों के लिए उच्च-स्तरीय थ्रेडिंग मॉड्यूल का उपयोग करना चाहिए जिन्हें आप परिनियोजित करना चाहते हैं। थ्रेड मॉड्यूल केवल शैक्षिक उद्देश्यों के लिए यहां कवर किया गया है।
धागा मॉड्यूल
इस मॉड्यूल का उपयोग करके एक नया धागा बनाने का सिंटैक्स इस प्रकार है:
thread.start_new_thread(function_name, arguments)
ठीक है, अब आपने कोडिंग शुरू करने के लिए मूल सिद्धांत को कवर किया है। इसलिए, अपना IDLE या नोटपैड खोलें और निम्नलिखित में टाइप करें:
import timeimport _threaddef thread_test(name, wait):i = 0while i <= 3:time.sleep(wait)print("Running %s\n" %name)i = i + 1print("%s has finished execution" %name)if __name__ == "__main__":_thread.start_new_thread(thread_test, ("First Thread", 1))_thread.start_new_thread(thread_test, ("Second Thread", 2))_thread.start_new_thread(thread_test, ("Third Thread", 3))
प्रोग्राम को चलाने के लिए फ़ाइल को सहेजें और F5 को हिट करें। यदि सब कुछ सही ढंग से किया गया था, तो यह आउटपुट है जिसे आपको देखना चाहिए:
आप दौड़ स्थितियों के बारे में और आगामी अनुभागों में उन्हें संभालने के बारे में अधिक जानेंगे
कोड परीक्षा
- ये कथन समय और थ्रेड मॉड्यूल को आयात करते हैं जो कि पायथन थ्रेड्स के निष्पादन और विलंब को संभालने के लिए उपयोग किए जाते हैं।
- यहां, आपने थ्रेड_टेस्ट नामक एक फ़ंक्शन को परिभाषित किया है , जिसे start_new_thread विधि द्वारा बुलाया जाएगा । फ़ंक्शन चार पुनरावृत्तियों के लिए थोड़ी देर लूप चलाता है और थ्रेड के नाम को प्रिंट करता है जो इसे कहते हैं। एक बार पुनरावृत्ति पूर्ण हो जाने पर, यह संदेश को यह कहते हुए प्रिंट करता है कि थ्रेड ने निष्पादन समाप्त कर दिया है।
- यह आपके कार्यक्रम का मुख्य भाग है। यहां, आप बस start_new_thread पद्धति को एक तर्क के रूप में थ्रेड_टेस्ट फ़ंक्शन के साथ कहते हैं ।
यह उस फ़ंक्शन के लिए एक नया थ्रेड बनाएगा जिसे आप तर्क के रूप में पास करते हैं और इसे निष्पादित करना शुरू करते हैं। ध्यान दें कि आप इसे (थ्रेड _ टेस्ट) किसी अन्य फ़ंक्शन के साथ बदल सकते हैं जिसे आप थ्रेड के रूप में चलाना चाहते हैं।
थ्रेडिंग मॉड्यूल
यह मॉड्यूल बहु-स्तरीय अनुप्रयोगों में प्रबंधन के लिए अजगर में थ्रेडिंग का उच्च-स्तरीय कार्यान्वयन और वास्तविक मानक है। यह थ्रेड मॉड्यूल की तुलना में सुविधाओं की एक विस्तृत श्रृंखला प्रदान करता है।

इस मॉड्यूल में परिभाषित कुछ उपयोगी कार्यों की सूची इस प्रकार है:
कार्य का नाम | विवरण |
सक्रिय | थ्रेड ऑब्जेक्ट्स की गिनती लौटाता है जो अभी भी जीवित हैं |
चालू | थ्रेड वर्ग की वर्तमान ऑब्जेक्ट देता है। |
गणना करना () | सभी सक्रिय थ्रेड ऑब्जेक्ट्स को सूचीबद्ध करता है। |
isDaemon () | सच है अगर धागा एक डेमन है। |
जिंदा है() | यदि धागा अभी भी जीवित है तो सच लौटाता है। |
थ्रेड क्लास के तरीके | |
शुरू() | एक सूत्र की गतिविधि शुरू करता है। इसे प्रत्येक थ्रेड के लिए केवल एक बार कॉल किया जाना चाहिए क्योंकि यह रनटाइम त्रुटि को फेंक देगा यदि कई बार कहा जाता है। |
Daud() | यह विधि एक थ्रेड की गतिविधि को दर्शाती है और थ्रेड क्लास को विस्तारित करने वाले वर्ग द्वारा ओवरराइड किया जा सकता है। |
शामिल हों () | यह अन्य कोड के निष्पादन को रोकता है जब तक कि थ्रेड () विधि को शामिल नहीं किया गया था। |
बैकस्टोरी: द थ्रेड क्लास
इससे पहले कि आप थ्रेडिंग मॉड्यूल का उपयोग करके मल्टीथ्रेडेड प्रोग्राम को कोड करना शुरू कर दें, थ्रेड क्लास के बारे में समझना महत्वपूर्ण है। थ्रेड क्लास वह प्राइमरी क्लास होती है जो टेम्पलेट को और अजगर में एक थ्रेड के संचालन को परिभाषित करती है।
मल्टीथ्रेडेड पायथन एप्लिकेशन बनाने का सबसे आम तरीका एक वर्ग घोषित करना है जो थ्रेड क्लास का विस्तार करता है और इसे चलाने () विधि को ओवरराइड करता है।
सारांश में थ्रेड क्लास, एक कोड अनुक्रम दर्शाता है जो नियंत्रण के एक अलग थ्रेड में चलता है ।
इसलिए, जब एक multithreaded ऐप लिखते हैं, तो आप निम्न कार्य करेंगे:
- एक वर्ग परिभाषित करें जो थ्रेड वर्ग का विस्तार करता है
- ओवरराइड करें __init__ कंस्ट्रक्टर
- रन () विधि को ओवरराइड करें
एक बार जब कोई थ्रेड ऑब्जेक्ट बना दिया जाता है, तो इस गतिविधि का निष्पादन शुरू करने के लिए स्टार्ट () विधि का उपयोग किया जा सकता है और वर्तमान गतिविधि समाप्त होने तक अन्य सभी कोड को ब्लॉक करने के लिए जॉइन () विधि का उपयोग किया जा सकता है।
अब, अपने पिछले उदाहरण को लागू करने के लिए थ्रेडिंग मॉड्यूल का उपयोग करने का प्रयास करें। फिर से, अपनी IDLE को फायर करें और निम्नलिखित में टाइप करें:
import timeimport threadingclass threadtester (threading.Thread):def __init__(self, id, name, i):threading.Thread.__init__(self)self.id = idself.name = nameself.i = idef run(self):thread_test(self.name, self.i, 5)print ("%s has finished execution " %self.name)def thread_test(name, wait, i):while i:time.sleep(wait)print ("Running %s \n" %name)i = i - 1if __name__=="__main__":thread1 = threadtester(1, "First Thread", 1)thread2 = threadtester(2, "Second Thread", 2)thread3 = threadtester(3, "Third Thread", 3)thread1.start()thread2.start()thread3.start()thread1.join()thread2.join()thread3.join()
जब आप उपरोक्त कोड निष्पादित करेंगे तो यह आउटपुट होगा:
कोड परीक्षा
- यह हिस्सा हमारे पिछले उदाहरण जैसा ही है। यहां, आप उस समय और थ्रेड मॉड्यूल को आयात करते हैं जो पायथन थ्रेड्स के निष्पादन और देरी को संभालने के लिए उपयोग किया जाता है।
- इस बिट में, आप थ्रेडस्टर नामक एक क्लास बना रहे हैं, जो थ्रेडिंग मॉड्यूल के थ्रेड क्लास को इनहेरिट या विस्तारित करता है । यह अजगर में धागे बनाने के सबसे आम तरीकों में से एक है। हालांकि, आपको अपने ऐप में केवल कंस्ट्रक्टर और रन () विधि को ओवरराइड करना चाहिए । जैसा कि आप उपरोक्त कोड नमूने में देख सकते हैं, __init__ विधि (निर्माता) ओवरराइड हो गई है।
इसी तरह, आपने रन () विधि को भी ओवरराइड कर दिया है । इसमें वह कोड होता है जिसे आप किसी थ्रेड के अंदर निष्पादित करना चाहते हैं। इस उदाहरण में, आपने थ्रेड_टेस्ट () फ़ंक्शन को कॉल किया है।
- यह थ्रेड_टेस्ट () विधि है जो एक तर्क के रूप में i का मान लेता है, इसे प्रत्येक पुनरावृत्ति में 1 से कम करता है और बाकी कोड के माध्यम से छोरों तक मैं 0. हो जाता है। प्रत्येक पुनरावृत्ति में, यह वर्तमान में थ्रेड के नाम को प्रिंट करता है और प्रतीक्षा सेकंड के लिए सोता है (जिसे एक तर्क के रूप में भी लिया जाता है)।
- थ्रेड 1 = थ्रेडस्टर (1, "फर्स्ट थ्रेड", 1)
यहां, हम एक सूत्र बना रहे हैं और तीन मापदंडों को पारित कर रहे हैं जिन्हें हमने __in__ में घोषित किया है। पहला पैरामीटर थ्रेड की आईडी है, दूसरा पैरामीटर थ्रेड का नाम है, और तीसरा पैरामीटर काउंटर है, जो निर्धारित करता है कि लूप कितनी बार चलना चाहिए।
- thread2.start ()
थ्रेड का निष्पादन शुरू करने के लिए स्टार्ट विधि का उपयोग किया जाता है। आंतरिक रूप से, प्रारंभ () फ़ंक्शन आपकी कक्षा की रन () विधि को कॉल करता है।
- thread3.join ()
सम्मिलित () विधि अन्य कोड के निष्पादन को रोकती है और उस थ्रेड तक इंतजार करती है जिस पर इसे फिनिश कहा जाता था।
जैसा कि आप पहले से ही जानते हैं, जो धागे एक ही प्रक्रिया में हैं, उस प्रक्रिया की मेमोरी और डेटा तक पहुंच है। परिणामस्वरूप, यदि एक से अधिक थ्रेड डेटा को एक साथ बदलने या एक्सेस करने का प्रयास करते हैं, तो त्रुटियां समाप्त हो सकती हैं।
अगले भाग में, आप विभिन्न प्रकार की जटिलताओं को देखेंगे जो मौजूदा एक्सेस लेनदेन के लिए जाँच के बिना थ्रेड डेटा और महत्वपूर्ण-सेक्शन तक पहुँच सकते हैं।
गतिरोध और दौड़ की स्थिति
गतिरोध और दौड़ की स्थिति के बारे में जानने से पहले, समवर्ती प्रोग्रामिंग से संबंधित कुछ बुनियादी परिभाषाओं को समझना उपयोगी होगा:
- महत्वपूर्ण अनुभाग
यह कोड का एक टुकड़ा है जो साझा चर को एक्सेस या संशोधित करता है और इसे परमाणु लेनदेन के रूप में निष्पादित किया जाना चाहिए।
- संदर्भ स्विच
यह प्रक्रिया है कि एक सीपीयू एक कार्य से दूसरे में बदलने से पहले एक थ्रेड की स्थिति को स्टोर करने के लिए अनुसरण करता है ताकि बाद में उसी बिंदु से फिर से शुरू किया जा सके।
गतिरोध
डेडलॉक सबसे ज्यादा आशंका वाला मुद्दा है, जो डेवलपर्स का सामना करते हैं जब अजगर में समवर्ती / मल्टीथ्रेडेड एप्लिकेशन लिखते हैं। डेडलॉक को समझने का सबसे अच्छा तरीका क्लासिक कंप्यूटर विज्ञान उदाहरण समस्या है जिसे डाइनिंग फिलोसोफर्स समस्या के रूप में जाना जाता है ।
भोजन दार्शनिकों के लिए समस्या का विवरण इस प्रकार है:
पाँच दार्शनिकों को गोलाकार (पास्ता का एक प्रकार) की पाँच प्लेटों और पाँच कांटों के साथ एक गोल मेज पर बैठाया जाता है, जैसा कि चित्र में दिखाया गया है।

किसी भी समय, एक दार्शनिक को या तो भोजन करना चाहिए या सोचना चाहिए।
इसके अलावा, एक दार्शनिक को उससे सटे दो कांटे (यानी, बाएं और दाएं कांटे) लेने चाहिए, इससे पहले कि वह स्पेगेटी खा सके। गतिरोध की समस्या तब होती है जब सभी पांच दार्शनिक एक साथ अपने सही कांटे उठाते हैं।
चूंकि दार्शनिकों में से प्रत्येक के पास एक कांटा है, इसलिए वे सभी अपने कांटे को नीचे रखने के लिए दूसरों की प्रतीक्षा करेंगे। नतीजतन, उनमें से कोई भी स्पेगेटी खाने में सक्षम नहीं होगा।
इसी तरह, एक समवर्ती प्रणाली में, एक गतिरोध तब होता है जब विभिन्न धागे या प्रक्रियाएं (दार्शनिक) एक ही समय में साझा सिस्टम संसाधनों (कांटे) को प्राप्त करने का प्रयास करते हैं। नतीजतन, किसी भी प्रक्रिया को निष्पादित करने का मौका नहीं मिलता है क्योंकि वे किसी अन्य प्रक्रिया द्वारा आयोजित किसी अन्य संसाधन की प्रतीक्षा कर रहे हैं।
दौर कि शर्ते
एक दौड़ की स्थिति एक कार्यक्रम की अवांछित स्थिति है जो तब होती है जब एक सिस्टम एक साथ दो या अधिक ऑपरेशन करता है। उदाहरण के लिए, लूप के लिए इस सरल पर विचार करें:
i=0; # a global variablefor x in range(100):print(i)i+=1;
आप बनाते हैं n सूत्र जो एक बार में इस कोड को चलाने की संख्या, आप (जो धागे द्वारा साझा किया जाता है) जब प्रोग्राम निष्पादन खत्म मैं का मूल्य निर्धारित नहीं कर सकते। ऐसा इसलिए है क्योंकि एक वास्तविक मल्टीथ्रेडिंग वातावरण में, थ्रेड्स ओवरलैप हो सकते हैं, और एक थ्रेड द्वारा पुनर्प्राप्त और संशोधित किए गए i का मान जब किसी अन्य थ्रेड तक पहुंचता है, तो इसके बीच में परिवर्तन हो सकता है।
ये समस्याओं के दो मुख्य वर्ग हैं जो एक बहुस्तरीय या वितरित अजगर आवेदन में हो सकते हैं। अगले भाग में, आप सीखेंगे कि थ्रेड्स को सिंक्रनाइज़ करके इस समस्या को कैसे दूर किया जाए।
धागे को सिंक्रोनाइज़ करना
दौड़ की स्थिति, गतिरोध और अन्य थ्रेड-आधारित समस्याओं से निपटने के लिए, थ्रेडिंग मॉड्यूल लॉक ऑब्जेक्ट प्रदान करता है । विचार यह है कि जब कोई थ्रेड किसी विशिष्ट संसाधन तक पहुँच चाहता है, तो वह उस संसाधन के लिए लॉक प्राप्त कर लेता है। एक बार जब कोई थ्रेड किसी विशेष संसाधन को लॉक कर देता है, तो कोई भी थ्रेड इसे तब तक एक्सेस नहीं कर सकता जब तक कि लॉक जारी न हो जाए। नतीजतन, संसाधन में परिवर्तन परमाणु होगा, और दौड़ की स्थिति को रोक दिया जाएगा।
एक लॉक निम्न-स्तरीय सिंक्रनाइज़ेशन आदिम है जिसे __thread मॉड्यूल द्वारा कार्यान्वित किया जाता है । किसी भी समय, एक लॉक 2 राज्यों में से एक में हो सकता है: लॉक या अनलॉक किया गया। यह दो तरीकों का समर्थन करता है:
- प्राप्त करना ()
जब लॉक-स्टेट अनलॉक किया जाता है, तो अधिग्रहित () विधि को कॉल करने से स्थिति लॉक और वापस आ जाएगी। हालाँकि, यदि स्थिति लॉक है, तो रिलीज़ () विधि द्वारा कॉल को प्राप्त करने () को अवरुद्ध कर दिया जाता है, जिसे किसी अन्य थ्रेड द्वारा कहा जाता है।
- जारी ()
रिलीज़ () विधि का उपयोग राज्य को अनलॉक करने के लिए सेट करने के लिए किया जाता है, अर्थात, लॉक को रिलीज़ करने के लिए। इसे किसी भी धागे से बुलाया जा सकता है, जरूरी नहीं कि लॉक को अधिग्रहित किया जाए।
यहां आपके ऐप्स में ताले का उपयोग करने का एक उदाहरण है। अपना IDLE फायर करें और निम्नलिखित टाइप करें:
import threadinglock = threading.Lock()def first_function():for i in range(5):lock.acquire()print ('lock acquired')print ('Executing the first funcion')lock.release()def second_function():for i in range(5):lock.acquire()print ('lock acquired')print ('Executing the second funcion')lock.release()if __name__=="__main__":thread_one = threading.Thread(target=first_function)thread_two = threading.Thread(target=second_function)thread_one.start()thread_two.start()thread_one.join()thread_two.join()
अब, F5 मारा। आपको इस तरह एक आउटपुट देखना चाहिए:
कोड परीक्षा
- यहाँ, आप केवल थ्रेडिंग (।) फ़ैक्टरी फ़ंक्शन को कॉल करके एक नया लॉक बना रहे हैं । आंतरिक रूप से, लॉक () प्लेटफ़ॉर्म द्वारा बनाए रखा गया सबसे प्रभावी कंक्रीट लॉक क्लास का एक उदाहरण देता है।
- पहले बयान में, आप अधिग्रहित () विधि को कॉल करके लॉक प्राप्त करते हैं। जब लॉक प्रदान किया गया है, तो आप कंसोल पर "लॉक अधिग्रहित" प्रिंट करें । एक बार सभी कोड जिसे आप चलाना चाहते हैं, निष्पादन समाप्त हो गया है, आप रिलीज़ () विधि को कॉल करके लॉक रिलीज़ करते हैं।
सिद्धांत ठीक है, लेकिन आप कैसे जानते हैं कि ताला वास्तव में काम करता था? यदि आप आउटपुट को देखते हैं, तो आप देखेंगे कि प्रत्येक प्रिंट स्टेटमेंट एक बार में एक लाइन को प्रिंट कर रहा है। स्मरण करें कि, पहले के उदाहरण में, प्रिंट से आउटपुट जहां हाफज़र्ड हैं क्योंकि एक ही समय में कई थ्रेड प्रिंट () विधि तक पहुंच रहे थे। यहां, लॉक के अधिग्रहण के बाद ही प्रिंट फ़ंक्शन को कहा जाता है। तो, आउटपुट को एक बार में प्रदर्शित किया जाता है और लाइन से लाइन।
ताले के अलावा, अजगर भी नीचे सूचीबद्ध के रूप में धागा तुल्यकालन को संभालने के लिए कुछ अन्य तंत्रों का समर्थन करता है:
- RLocks
- सेमफोरस
- शर्तेँ
- घटनाएँ, और
- बाधाओं
ग्लोबल इंटरप्रेटर लॉक (और इससे कैसे निपटें)
अजगर के GIL के विवरण में आने से पहले, आइए कुछ शब्दों को परिभाषित करते हैं जो आगामी अनुभाग को समझने में उपयोगी होंगे:
- सीपीयू-बाउंड कोड: यह किसी भी कोड के कोड को संदर्भित करता है जिसे सीधे सीपीयू द्वारा निष्पादित किया जाएगा।
- I / O- बाउंड कोड: यह कोई भी कोड हो सकता है जो OS के फाइल सिस्टम को एक्सेस करता है
- CPython: यह Python का संदर्भ कार्यान्वयन है और इसे C और Python (प्रोग्रामिंग भाषा) में लिखे गए व्याख्याकार के रूप में वर्णित किया जा सकता है।
पायथन में GIL क्या है?
अजगर में ग्लोबल इंटरप्रेटर लॉक (जीआईएल) एक प्रक्रिया लॉक या एक म्यूटेक्स है जिसका उपयोग प्रक्रियाओं से निपटने के दौरान किया जाता है। यह सुनिश्चित करता है कि एक धागा एक समय में एक विशेष संसाधन तक पहुंच सकता है और यह एक बार में वस्तुओं और बायोटेक के उपयोग को भी रोकता है। यह एक प्रदर्शन वृद्धि में एकल-थ्रेडेड प्रोग्राम्स को लाभ देता है। अजगर में जीआईएल बहुत सरल और लागू करने में आसान है।
एक लॉक का उपयोग यह सुनिश्चित करने के लिए किया जा सकता है कि किसी निश्चित समय में केवल एक थ्रेड के पास किसी विशेष संसाधन तक पहुंच हो।
पायथन की एक विशेषता यह है कि यह प्रत्येक दुभाषिया प्रक्रिया पर एक वैश्विक ताला का उपयोग करता है, जिसका अर्थ है कि प्रत्येक प्रक्रिया अजगर दुभाषिया को एक संसाधन के रूप में मानती है।
उदाहरण के लिए, मान लीजिए कि आपने एक पायथन प्रोग्राम लिखा है, जो सीपीयू और 'आई / ओ' दोनों ऑपरेशंस करने के लिए दो थ्रेड्स का उपयोग करता है। जब आप इस कार्यक्रम को निष्पादित करते हैं, तो यह होता है:
- अजगर दुभाषिया एक नई प्रक्रिया बनाता है और थ्रेड्स को जन्म देता है
- जब थ्रेड -1 चलना शुरू होता है, तो यह पहले जीआईएल का अधिग्रहण करेगा और इसे लॉक कर देगा।
- यदि थ्रेड -2 अब निष्पादित करना चाहता है, तो उसे GIL के जारी होने का इंतजार करना होगा, भले ही कोई अन्य प्रोसेसर मुक्त हो।
- अब, मान लीजिए कि थ्रेड -1 I / O ऑपरेशन की प्रतीक्षा कर रहा है। इस समय, यह जीआईएल जारी करेगा, और थ्रेड -2 इसका अधिग्रहण करेगा।
- I / O ऑप्स को पूरा करने के बाद, यदि थ्रेड -1 अब निष्पादित करना चाहता है, तो उसे फिर से थ्रेड -2 द्वारा GIL जारी होने का इंतजार करना होगा।
इसके कारण, केवल एक धागा किसी भी समय दुभाषिया तक पहुंच सकता है, जिसका अर्थ है कि किसी दिए गए बिंदु पर केवल एक धागा निष्पादन अजगर कोड होगा।
यह सिंगल-कोर प्रोसेसर में ठीक है क्योंकि यह थ्रेड्स को संभालने के लिए टाइम स्लाइसिंग (इस ट्यूटोरियल के पहले भाग को देखें) का उपयोग करेगा। हालांकि, मल्टी-कोर प्रोसेसर के मामले में, कई थ्रेड्स पर निष्पादित सीपीयू-बाउंड फ़ंक्शन का कार्यक्रम की दक्षता पर काफी प्रभाव पड़ेगा क्योंकि यह वास्तव में एक ही समय में सभी उपलब्ध कोर का उपयोग नहीं करेगा।
GIL की आवश्यकता क्यों थी?
CPython कचरा संग्रहकर्ता एक कुशल मेमोरी मैनेजमेंट तकनीक का उपयोग करता है जिसे संदर्भ गणना के रूप में जाना जाता है। यहां बताया गया है कि यह कैसे काम करता है: अजगर में हर वस्तु की एक संदर्भ गणना होती है, जो तब बढ़ जाती है जब इसे एक नए चर नाम को सौंपा जाता है या कंटेनर में जोड़ा जाता है (जैसे ट्यूपल्स, सूचियां, आदि)। इसी तरह, संदर्भ की संख्या कम हो जाती है जब संदर्भ दायरे से बाहर हो जाता है या जब डेल स्टेटमेंट कहा जाता है। जब किसी ऑब्जेक्ट की संदर्भ संख्या 0 तक पहुंचती है, तो यह कचरा एकत्र किया जाता है, और आवंटित मेमोरी को मुक्त कर दिया जाता है।
लेकिन समस्या यह है कि संदर्भ गणना चर किसी भी अन्य वैश्विक चर की तरह दौड़ की स्थिति से ग्रस्त है। इस समस्या को हल करने के लिए, अजगर के डेवलपर्स ने वैश्विक दुभाषिया लॉक का उपयोग करने का निर्णय लिया। अन्य विकल्प प्रत्येक ऑब्जेक्ट में एक लॉक जोड़ना था, जिसके परिणामस्वरूप गतिरोध और अधिग्रहण () और रिलीज़ () कॉल से ओवरहेड बढ़ेगा।
इसलिए, जीआईएल भारी सीपीयू-बाउंड ऑपरेशन चलाने वाले मल्टीथ्रेडेड पायथन कार्यक्रमों के लिए एक महत्वपूर्ण प्रतिबंध है (प्रभावी रूप से उन्हें एकल-थ्रेडेड बनाते हुए)। यदि आप अपने आवेदन में कई सीपीयू कोर का उपयोग करना चाहते हैं, तो इसके बजाय मल्टीप्रोसेसिंग मॉड्यूल का उपयोग करें।
सारांश
- मल्टीथ्रेडिंग के लिए पायथन 2 मॉड्यूल का समर्थन करता है:
- __thread मॉड्यूल: यह थ्रेडिंग के लिए निम्न-स्तरीय कार्यान्वयन प्रदान करता है और अप्रचलित है।
- थ्रेडिंग मॉड्यूल : यह मल्टीथ्रेडिंग के लिए एक उच्च-स्तरीय कार्यान्वयन प्रदान करता है और वर्तमान मानक है।
- सूत्रण मॉड्यूल का उपयोग करके एक धागा बनाने के लिए, आपको निम्नलिखित कार्य करना चाहिए:
- एक क्लास बनाएं जो थ्रेड क्लास का विस्तार करे ।
- इसके निर्माता को ओवरराइड करें (__init__)।
- इसकी रन () विधि को ओवरराइड करें ।
- इस वर्ग की एक वस्तु बनाएँ।
- प्रारंभ () विधि को कॉल करके एक थ्रेड निष्पादित किया जा सकता है ।
- में शामिल होने के () विधि इस सूत्र (जिस पर शामिल होने के लिए बुलाया गया था) निष्पादन खत्म जब तक अन्य थ्रेड ब्लॉक करने के लिए इस्तेमाल किया जा सकता।
- एक दौड़ की स्थिति तब होती है जब एक ही समय में कई थ्रेड्स साझा संसाधन तक पहुँचते हैं या संशोधित करते हैं।
- धागे को सिंक्रोनाइज़ करके इससे बचा जा सकता है।
- धागे को सिंक्रनाइज़ करने के लिए पायथन 6 तरीकों का समर्थन करता है:
- ताले
- RLocks
- सेमफोरस
- शर्तेँ
- घटनाएँ, और
- बाधाओं
- ताले केवल एक विशेष धागे की अनुमति देते हैं जिसने महत्वपूर्ण खंड में प्रवेश करने के लिए ताला का अधिग्रहण किया है।
- एक ताला में 2 प्राथमिक विधियाँ हैं:
- अधिग्रहण () : यह लॉक स्टेट को लॉक करने के लिए सेट करता है । यदि एक बंद वस्तु पर कॉल किया जाता है, तो यह संसाधन मुक्त होने तक अवरुद्ध हो जाता है।
- रिलीज () : यह लॉक स्टेट को अनलॉक और रिटर्न के लिए सेट करता है। यदि किसी अनलॉक की गई वस्तु पर कॉल किया जाता है, तो यह गलत है।
- वैश्विक दुभाषिया ताला एक ऐसा तंत्र है जिसके माध्यम से एक समय में केवल 1 सीपीथॉन दुभाषिया प्रक्रिया ही चल सकती है।
- इसका उपयोग CPythons के कचरा संग्राहक की संदर्भ गणना की कार्यक्षमता को सुविधाजनक बनाने के लिए किया गया था।
- भारी सीपीयू-बाउंड ऑपरेशन वाले पायथन ऐप बनाने के लिए, आपको मल्टीप्रोसेसिंग मॉड्यूल का उपयोग करना चाहिए।