Python में `concurrent` मॉड्यूल
इस लेख में, हम Python के concurrent मॉड्यूल को समझाएंगे।
Concurrency और Parallelism की अवधारणाओं को स्पष्ट करते हुए, हम व्यावहारिक उदाहरणों के साथ बताएंगे कि concurrent मॉड्यूल का उपयोग करके asynchronous प्रोसेसिंग कैसे लागू करें।
YouTube Video
Python में concurrent मॉड्यूल
Python में प्रक्रिया को तेज करते समय, concurrency और parallelism के बीच के अंतर को समझना महत्वपूर्ण है। concurrent मॉड्यूल एक महत्वपूर्ण तरीका है जिससे आप इन अंतर को ध्यान में रखते हुए asynchronous प्रोसेसिंग को सुरक्षित और सरल रूप से संभाल सकते हैं।
Concurrency और Parallelism के बीच का अंतर
-
Concurrency का अर्थ है प्रक्रिया को इस तरह डिजाइन करना कि कई कार्य छोटे-छोटे हिस्सों में एक-दूसरे के बीच स्विच करते हुए आगे बढ़ें। भले ही कार्य वास्तव में एक साथ नहीं चल रहे हों, लेकिन 'इंतजार के समय' का उपयोग करके आप संपूर्ण प्रक्रिया को और अधिक कुशल बना सकते हैं।
-
Parallelism एक ऐसी प्रक्रिया है जिसमें एक ही समय पर कई कार्य वास्तविक रूप से चलाए जाते हैं। कई CPU cores का उपयोग करके, प्रोसेसिंग एक साथ आगे बढ़ती है।
दोनों प्रोसेसिंग को तेज करने की तकनीकें हैं, परंतु concurrency 'कैसे आगे बढ़ें' का डिजाइन का विषय है, जबकि parallelism 'कैसे चलता है' का निष्पादन का विषय है, जिससे ये मूलतः अलग हैं।
concurrent मॉड्यूल क्या है?
concurrent Python की एक स्टैंडर्ड लाइब्रेरी है जो concurrency और parallelism को सुरक्षित और सरल रूप से संभालने के लिए हाई-लेवल API उपलब्ध कराती है। इसे इस तरह डिज़ाइन किया गया है कि आप केवल 'कार्य निष्पादन' पर ध्यान केंद्रित कर सकें, बिना threads या processes को बनाने और प्रबंधित करने जैसी लो-लेवल ऑपरेशन की चिंता किए।
ThreadPoolExecutor और ProcessPoolExecutor की भूमिकाएँ
concurrent मॉड्यूल कार्य की प्रकृति के आधार पर दो मुख्य विकल्प प्रदान करता है।
-
ThreadPoolExecutorयह concurrent implementations के लिए उपयुक्त है, विशेष रूप से उन कार्यों के लिए जिनमें कई I/O प्रतीक्षाएँ होती हैं, जैसे नेटवर्क या फाइल ऑपरेशन। कार्य के बीच स्विच करके, यह प्रतीक्षा के समय का प्रभावी उपयोग करता है। -
ProcessPoolExecutorयह implementation parallel प्रोसेसिंग के लिए है और CPU-सघन कार्यों के लिए उपयुक्त है। यह अनेक processes का उपयोग करता है ताकि उपलब्ध CPU cores का पूरा लाभ एक साथ उठाया जा सके।
इस प्रकार, concurrent मॉड्यूल की मुख्य विशेषता है कि यह आपको आवश्यकता अनुसार concurrency और parallelism के बीच उचित चयन की संरचना देता है।
ThreadPoolExecutor की मूल बातें (I/O कार्यों के लिए)
ThreadPoolExecutor I/O-बेस्ड कार्यों के लिए उपयुक्त है, जैसे नेटवर्क कम्युनिकेशन और फाइल ऑपरेशन। यह कार्यों को कई threads में बाँटता है, जिससे प्रतीक्षा के समय का प्रभावी उपयोग होता है।
1from concurrent.futures import ThreadPoolExecutor
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12 for future in futures:
13 print(future.result())- इस उदाहरण में, एक सेकंड तक प्रतीक्षा करने वाले अनेक I/O कार्य एक साथ चलाए जाते हैं।
submitका उपयोग करके, function कॉल asynchronous कार्यों के रूप में रजिस्टर किए जाते हैं, तथाresult()को कॉल करके आप पूर्णता की प्रतीक्षा कर सकते हैं और परिणाम प्राप्त कर सकते हैं, जिससे आप प्रतीक्षा के समय का प्रभावी और संक्षिप्त रूप में concurrent प्रोसेसिंग लागू कर सकते हैं।
map का उपयोग करके सरल concurrency
यदि जटिल नियंत्रण की आवश्यकता नहीं है, तो map का उपयोग आपके कोड को और भी संक्षिप्त बना सकता है।
1from concurrent.futures import ThreadPoolExecutor
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 results = executor.map(fetch_data, range(5))
11
12 for result in results:
13 print(result)- इस उदाहरण में, कई I/O कार्य
ThreadPoolExecutor.mapका उपयोग करके एक साथ चलाए जाते हैं।mapइनपुट के उसी क्रम में परिणाम लौटाता है, इसलिए आप ऐसा कोड लिख सकते हैं जो अनुक्रमिक प्रोसेसिंग के करीब हो, और asynchronous प्रोसेसिंग के बारे में सोचे बिना भी concurrency संभव हो जाती है—यह एक बड़ा लाभ है।
ProcessPoolExecutor की मूल बातें (CPU-बेस्ड कार्यों के लिए)
भारी गणना, जिसमें CPU का पूरा उपयोग होता है, के लिए आपको threads के बजाय processes का उपयोग करना चाहिए। यह आपको Global Interpreter Lock (GIL) की सीमा से बचने में मदद करता है।
1from concurrent.futures import ProcessPoolExecutor
2
3def heavy_calculation(n):
4 # Simulate a CPU-bound task
5 total = 0
6 for i in range(10_000_000):
7 total += i * n
8 return total
9
10if __name__ == "__main__":
11 with ProcessPoolExecutor(max_workers=4) as executor:
12 results = executor.map(heavy_calculation, range(4))
13
14 for result in results:
15 print(result)इस उदाहरण में, CPU-सघन गणनाएँ ProcessPoolExecutor का उपयोग करके समानांतर चलाई जाती हैं। चूंकि processes बनाने की आवश्यकता होती है, इसलिए __main__ guard आवश्यक है, जो कई CPU cores का उपयोग करके सुरक्षित parallel प्रोसेसिंग सक्षम बनाता है।
as_completed का उपयोग करके पूर्णता के क्रम में प्रोसेसिंग
as_completed तब उपयोगी है जब आप परिणामों को उसी क्रम में संभालना चाहते हैं जिसमें वे पूर्ण होते हैं।
1from concurrent.futures import ThreadPoolExecutor, as_completed
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12 for future in as_completed(futures):
13 print(future.result())- इस उदाहरण में, अनेक asynchronous कार्य एक साथ चलाए जाते हैं, और परिणाम उसी क्रम में प्राप्त होते हैं जिस क्रम में वे पूरा होते हैं।
as_completedका उपयोग करके आप कार्यों के क्रम की परवाह किए बिना तेजी से परिणाम संभाल सकते हैं, इससे यह प्रगति प्रदर्शित करने या अनुक्रमिक रूप से संभालने की आवश्यकता वाले हालात के लिए उपयुक्त है।
अपवादों का प्रबंधन
concurrent में, जब आप result() कॉल करते हैं तो अपवाद उठाए जाते हैं।
1from concurrent.futures import ThreadPoolExecutor
2
3def risky_task(n):
4 # Simulate a task that may fail for a specific input
5 if n == 3:
6 raise ValueError("Something went wrong")
7 return n * 2
8
9with ThreadPoolExecutor() as executor:
10 futures = [executor.submit(risky_task, i) for i in range(5)]
11
12 for future in futures:
13 try:
14 print(future.result())
15 except Exception as e:
16 print("Error:", e)- इस उदाहरण में दिखाया गया है कि अगर कुछ कार्यों में अपवाद आते हैं, तो भी अन्य कार्य चलते रहते हैं और परिणाम प्राप्त करते समय आप अपवादों को अलग-अलग संभाल सकते हैं।
concurrentकेFutureका उपयोग करके यह सुनिश्चित किया जाता है कि asynchronous प्रोसेसिंग की सफलताएँ और असफलताएँ सुरक्षित रूप से संभाली जा सकें।
Threads और Processes के बीच चयन करने के लिए दिशानिर्देश
Concurrency और parallelism का प्रभावी ढंग से उपयोग करने के लिए, कार्य की प्रकृति के अनुसार सही तरीका चुनना महत्वपूर्ण है।
व्यवहार में, निम्नलिखित मानदंड आपको निर्णय लेने में सहायता कर सकते हैं।
- संचार या फ़ाइल संचालन जैसे, जिन प्रक्रियाओं में बहुत अधिक I/O प्रतीक्षा होती है, उनके लिए
ThreadPoolExecutorका उपयोग करें। - CPU आधारिक, भारी गणनात्मक कार्यों के लिए,
ProcessPoolExecutorका उपयोग करें। - यदि बहुत से सरल कार्य हैं, तो
mapका उपयोग आपके कोड को और भी संक्षिप्त बना देगा। - यदि निष्पादन क्रम या अपवाद प्रबंधन पर सटीक नियंत्रण आवश्यक है, तो
submitकोas_completedके साथ संयोजित करें।
concurrent का उपयोग करने के लाभ
concurrent मॉड्यूल का उपयोग करके आप asynchronous प्रोसेसिंग को सुरक्षित और सहज रूप से संभाल सकते हैं।
मुख्य लाभ निम्नलिखित हैं:।
- आपको लो-लेवल thread या process प्रबंधन की चिंता नहीं करनी पड़ती।
- यह Python की स्टैंडर्ड लाइब्रेरी का हिस्सा है, इसलिए आप इसे निस्संकोच उपयोग कर सकते हैं।
- कोड अधिक पठनीय और मेंटेन करने योग्य बन जाता है।
- Concurrency और parallelism सीखने के पहले चरण के लिए यह आदर्श है।
इन दिशानिर्देशों को ध्यान में रखने से concurrent का उपयोग करते समय त्रुटियों की संभावना काफी कम हो जाती है।
सारांश
concurrent मॉड्यूल Python में व्यावहारिक concurrency और parallelism के लिए स्टैंडर्ड विकल्प है। यह आपको अपनी प्रक्रिया की सामग्री में बड़े बदलाव किए बिना प्रदर्शन को बढ़ाने की सुविधा देता है, जो वास्तविक अभ्यास में एक महत्वपूर्ण लाभ है। concurrent का उपयोग करके आप संक्षिप्त रूप में asynchronous प्रोसेसिंग लागू कर सकते हैं, साथ ही अपवाद प्रबंधन और निष्पादन नियंत्रण को सुरक्षित रूप से संभाल सकते हैं।
आप हमारे YouTube चैनल पर Visual Studio Code का उपयोग करके ऊपर दिए गए लेख के साथ आगे बढ़ सकते हैं। कृपया YouTube चैनल को भी देखें।