हाल के वर्षों में मल्टीकोर सीपीयू के आगमन के साथ, समानांतर प्रोग्रामिंग नए प्रसंस्करण कार्य घोड़ों का पूरा लाभ उठाने का तरीका है। समानांतर प्रोग्रामिंग एकाधिक प्रसंस्करण कोर की उपलब्धता के कारण प्रक्रियाओं के समवर्ती निष्पादन को संदर्भित करता है। यह, संक्षेप में, रैखिक सिंगल कोर निष्पादन या यहां तक कि मल्टीथ्रेडिंग के विपरीत कार्यक्रमों के प्रदर्शन और दक्षता में जबरदस्त बढ़ावा देता है। फोर्क/जॉइन फ्रेमवर्क जावा समवर्ती एपीआई का एक हिस्सा है। यह ढांचा प्रोग्रामर को एल्गोरिदम को समानांतर करने में सक्षम बनाता है। यह लेख जावा में उपलब्ध फोर्क/जॉइन फ्रेमवर्क की मदद से समानांतर प्रोग्रामिंग की अवधारणा की पड़ताल करता है।
एक सिंहावलोकन
समानांतर प्रोग्रामिंग का एक बहुत व्यापक अर्थ है और निस्संदेह कुछ पंक्तियों में विस्तृत करने के लिए एक विशाल क्षेत्र है। मामले की जड़ काफी सरल है, फिर भी इसे हासिल करना परिचालन रूप से बहुत कठिन है। सरल शब्दों में, समानांतर प्रोग्रामिंग का अर्थ है ऐसे प्रोग्राम लिखना जो किसी कार्य को पूरा करने के लिए एक से अधिक प्रोसेसर का उपयोग करते हैं, बस! अंदाज़ा लगाओ; यह परिचित लगता है, है ना? यह लगभग बहु सूत्रण के विचार के साथ तुकबंदी करता है। लेकिन, ध्यान दें कि उनके बीच कुछ महत्वपूर्ण अंतर हैं। सतह पर, वे समान हैं, लेकिन अंतर्धारा बिल्कुल अलग है। वास्तव में, बिना किसी वास्तविक समानांतर निष्पादन के समानांतर प्रसंस्करण का एक प्रकार का भ्रम प्रदान करने के लिए मल्टीथ्रेडिंग की शुरुआत की गई थी। मल्टीथ्रेडिंग वास्तव में क्या करता है कि यह CPU के निष्क्रिय समय को चुरा लेता है और इसका उपयोग अपने लाभ के लिए करता है।
संक्षेप में, मल्टीथ्रेडिंग कार्यों की असतत तार्किक इकाइयों का एक संग्रह है जो सीपीयू समय के अपने हिस्से को हथियाने के लिए चलता है, जबकि एक अन्य थ्रेड अस्थायी रूप से प्रतीक्षा कर रहा है, कहते हैं, कुछ उपयोगकर्ता इनपुट। निष्क्रिय CPU समय को प्रतिस्पर्धी थ्रेड्स के बीच बेहतर तरीके से साझा किया जाता है। यदि केवल एक सीपीयू है, तो यह समय साझा किया जाता है। यदि कई CPU कोर हैं, तो वे भी हमेशा साझा किए जाते हैं। इसलिए, एक इष्टतम मल्टीथ्रेडेड प्रोग्राम समय साझा करने के चतुर तंत्र द्वारा सीपीयू के प्रदर्शन को कम कर देता है। संक्षेप में, यह हमेशा एक सीपीयू का उपयोग करके एक धागा होता है जबकि दूसरा धागा प्रतीक्षा कर रहा होता है। यह एक सूक्ष्म तरीके से होता है कि उपयोगकर्ता को समानांतर प्रसंस्करण का अनुभव होता है, जहां वास्तव में, प्रसंस्करण वास्तव में त्वरित उत्तराधिकार में हो रहा है। मल्टीथ्रेडिंग का सबसे बड़ा लाभ यह है कि यह प्रोसेसिंग संसाधनों का अधिकतम लाभ उठाने की तकनीक है। अब, यह विचार काफी उपयोगी है और वातावरण के किसी भी सेट में उपयोग किया जा सकता है, चाहे इसमें एक सीपीयू या एकाधिक सीपीयू हों। विचार वही है।
दूसरी ओर, समानांतर प्रोग्रामिंग का अर्थ है कि कई समर्पित सीपीयू हैं जो प्रोग्रामर द्वारा समानांतर में उपयोग किए जाते हैं। इस प्रकार की प्रोग्रामिंग एक मल्टीकोर सीपीयू वातावरण के लिए अनुकूलित है। आज की अधिकांश मशीनें मल्टीकोर सीपीयू का उपयोग करती हैं। इसलिए, समानांतर प्रोग्रामिंग आजकल काफी प्रासंगिक है। यहां तक कि सबसे सस्ती मशीन में भी मल्टीकोर सीपीयू लगे होते हैं। हाथ से पकड़े जाने वाले उपकरणों को देखें; यहां तक कि वे मल्टीकोर हैं। हालाँकि मल्टीकोर सीपीयू के साथ सब कुछ हंकी-डोरी लगता है, यहाँ कहानी का दूसरा पक्ष भी है। क्या अधिक CPU कोर का मतलब तेज या कुशल कंप्यूटिंग है? हर बार नहीं! "जितना अधिक बेहतर" का लालची दर्शन न तो कंप्यूटिंग पर लागू होता है, न ही जीवन में। लेकिन वे वहाँ हैं, अनजाने में - दोहरे, क्वाड, ऑक्टा, और इसी तरह। वे ज्यादातर इसलिए हैं क्योंकि हम उन्हें चाहते हैं और इसलिए नहीं कि हमें उनकी जरूरत है, कम से कम ज्यादातर मामलों में। वास्तव में, दैनिक कंप्यूटिंग में एक भी सीपीयू को व्यस्त रखना अपेक्षाकृत कठिन है। हालांकि, मल्टीकोर का विशेष परिस्थितियों में उपयोग होता है, जैसे सर्वर, गेमिंग आदि में, या बड़ी समस्याओं को हल करना। कई सीपीयू होने की समस्या यह है कि इसके लिए मेमोरी की आवश्यकता होती है जो कि प्रोसेसिंग पावर के साथ-साथ लाइटनिंग फास्ट डेटा चैनल और अन्य एक्सेसरीज के साथ गति से मेल खाना चाहिए। संक्षेप में, दैनिक कंप्यूटिंग में कई सीपीयू कोर प्रदर्शन में सुधार प्रदान करते हैं जो इसका उपयोग करने के लिए आवश्यक संसाधनों की मात्रा से अधिक नहीं हो सकता है। नतीजतन, हमें एक कम उपयोग की गई महंगी मशीन मिलती है, जो शायद केवल दिखाने के लिए होती है।
समानांतर प्रोग्रामिंग
मल्टीथ्रेडिंग के विपरीत, जहां प्रत्येक कार्य एक बड़े कार्य की असतत तार्किक इकाई है, समानांतर प्रोग्रामिंग कार्य स्वतंत्र होते हैं और उनका निष्पादन क्रम मायने नहीं रखता। कार्यों को उनके द्वारा किए जाने वाले कार्य या प्रसंस्करण में उपयोग किए गए डेटा के अनुसार परिभाषित किया जाता है; इसे कार्यात्मक समानता . कहा जाता है या डेटा समानता , क्रमश। कार्यात्मक समानता में, प्रत्येक प्रोसेसर समस्या के अपने खंड पर काम करता है जबकि डेटा समांतरता में, प्रोसेसर डेटा के अपने खंड पर काम करता है। समानांतर प्रोग्रामिंग एक बड़े समस्या आधार के लिए उपयुक्त है जो एक एकल सीपीयू आर्किटेक्चर में फिट नहीं होता है, या यह समस्या इतनी बड़ी हो सकती है कि इसे समय के उचित अनुमान में हल नहीं किया जा सकता है। परिणामस्वरूप, प्रोसेसर के बीच वितरित किए जाने पर कार्य अपेक्षाकृत तेजी से परिणाम प्राप्त कर सकते हैं।
द फोर्क/जॉइन फ्रेमवर्क
फोर्क/जॉइन फ्रेमवर्क को java.util.concurrent . में परिभाषित किया गया है पैकेट। इसमें कई वर्ग और इंटरफेस शामिल हैं जो समानांतर प्रोग्रामिंग का समर्थन करते हैं। यह मुख्य रूप से क्या करता है कि यह कई थ्रेड निर्माण, उनके उपयोग की प्रक्रिया को सरल करता है, और कई प्रोसेसर के बीच प्रक्रिया आवंटन के तंत्र को स्वचालित करता है। इस ढांचे के साथ मल्टीथ्रेडिंग और समानांतर प्रोग्रामिंग के बीच उल्लेखनीय अंतर बहुत कुछ वैसा ही है जैसा हमने पहले उल्लेख किया था। यहां, प्रसंस्करण भाग को मल्टीथ्रेडिंग के विपरीत कई प्रोसेसर का उपयोग करने के लिए अनुकूलित किया गया है, जहां एकल सीपीयू के निष्क्रिय समय को साझा समय के आधार पर अनुकूलित किया जाता है। इस ढांचे के साथ अतिरिक्त लाभ समानांतर निष्पादन वातावरण में मल्टीथ्रेडिंग का उपयोग करना है। वहाँ कोई नुकसान नहीं।
इस ढांचे में चार मुख्य वर्ग हैं:
- ForkJoinTask
: यह एक अमूर्त वर्ग है जो एक कार्य को परिभाषित करता है। आमतौर पर, fork() . की मदद से एक टास्क बनाया जाता है इस वर्ग में परिभाषित विधि। यह कार्य लगभग थ्रेड . के साथ बनाए गए सामान्य थ्रेड के समान है वर्ग, लेकिन इससे हल्का है। यह जिस तंत्र को लागू करता है वह यह है कि यह बड़ी संख्या में कार्यों के प्रबंधन को कम संख्या में वास्तविक थ्रेड्स की मदद से सक्षम बनाता है जो ForkJoinPool में शामिल होते हैं। . कांटा () विधि आह्वान कार्य के अतुल्यकालिक निष्पादन को सक्षम करती है। शामिल हों () विधि तब तक प्रतीक्षा करने में सक्षम बनाती है जब तक कि जिस कार्य को इसे कहा जाता है उसे अंत में समाप्त नहीं किया जाता है। एक और तरीका है, जिसे invoke() . कहा जाता है , जो कांटा . को जोड़ती है और शामिल हों एक ही कॉल में संचालन। - फोर्कजॉइनपूल: यह वर्ग ForkJoinTask . के निष्पादन को प्रबंधित करने के लिए एक साझा पूल प्रदान करता है कार्य। यह मूल रूप से गैर-ForkJoinTask . से सबमिशन के लिए प्रवेश बिंदु प्रदान करता है क्लाइंट, साथ ही प्रबंधन और निगरानी संचालन।
- पुनरावर्ती क्रिया: यह ForkJoinTask . का एक सार विस्तार भी है कक्षा। आम तौर पर, हम इस वर्ग का विस्तार एक ऐसा कार्य बनाने के लिए करते हैं जो परिणाम नहीं देता है या जिसमें शून्य है वापसी प्रकार। गणना () इस वर्ग में परिभाषित विधि को कार्य के कम्प्यूटेशनल कोड को शामिल करने के लिए ओवरराइड किया गया है।
- पुनरावर्ती कार्य
: यह ForkJoinTask . का एक और सार विस्तार है कक्षा। हम एक परिणाम देने वाले कार्य को बनाने के लिए इस वर्ग का विस्तार करते हैं। और, ResursiveAction के समान, इसमें एक संरक्षित सार कंप्यूट () . भी शामिल है तरीका। कार्य के गणना भाग को शामिल करने के लिए इस पद्धति को ओवरराइड किया गया है।
फोर्क/फ्रेमवर्क रणनीति में शामिल हों
यह ढांचा एक पुनरावर्ती फूट डालो और जीतो का उपयोग करता है समानांतर प्रसंस्करण को लागू करने की रणनीति। यह मूल रूप से एक कार्य को छोटे उप-कार्यों में विभाजित करता है; फिर, प्रत्येक उप-कार्य को आगे उप-उप-कार्यों में विभाजित किया जाता है। इस प्रक्रिया को प्रत्येक कार्य पर पुनरावर्ती रूप से तब तक लागू किया जाता है जब तक कि यह क्रमिक रूप से संभालने के लिए पर्याप्त छोटा न हो। मान लीजिए कि हमें N . की एक सरणी के मानों को बढ़ाना है संख्याएं। यह कार्य है। अब, हम सरणी को दो उप-कार्य बनाकर विभाजित कर सकते हैं। उनमें से प्रत्येक को फिर से दो और उप-कार्यों में विभाजित करें, और इसी तरह। इस तरह, हम एक फूट डालो और जीतो . लागू कर सकते हैं जब तक कार्यों को एक इकाई समस्या में एकल नहीं किया जाता है, तब तक पुनरावर्ती रणनीति। यह इकाई समस्या तब उपलब्ध कई कोर प्रोसेसर द्वारा समानांतर में निष्पादित की जा सकती है। एक गैर-समानांतर वातावरण में, हमें जो करना है वह पूरे सरणी के माध्यम से चक्र है और अनुक्रम में प्रसंस्करण करना है। समानांतर प्रसंस्करण को देखते हुए यह स्पष्ट रूप से एक अक्षम दृष्टिकोण है। लेकिन, असली सवाल यह है कि क्या हर समस्या विभाजित और जीती जा सकती है ? निश्चित रूप से नहीं! लेकिन, ऐसी समस्याएं हैं जिनमें अक्सर डेटा के समूहीकरण के किसी प्रकार की सरणी, संग्रह शामिल होता है जो विशेष रूप से इस दृष्टिकोण के अनुकूल होता है। वैसे, ऐसी समस्याएं हैं जो डेटा के संग्रह का उपयोग नहीं कर सकती हैं फिर भी समानांतर प्रोग्रामिंग के लिए रणनीति का उपयोग करने के लिए अनुकूलित किया जा सकता है। समानांतर एल्गोरिदम पर समानांतर प्रसंस्करण या चर्चा के लिए किस प्रकार की कम्प्यूटेशनल समस्याएं उपयुक्त हैं, इस लेख के दायरे से बाहर है। आइए फोर्क/जॉइन फ्रेमवर्क के आवेदन पर एक त्वरित उदाहरण देखें।
एक त्वरित उदाहरण
यह एक बहुत ही सरल उदाहरण है जो आपको जावा में फोर्क/जॉइन फ्रेमवर्क के साथ समानांतरवाद को लागू करने के बारे में एक विचार देने के लिए है।
package org.mano.example; import java.util.concurrent.RecursiveAction; public class CustomRecursiveAction extends RecursiveAction { final int THRESHOLD = 2; double [] numbers; int indexStart, indexLast; CustomRecursiveAction(double [] n, int s, int l) { numbers = n; indexStart = s; indexLast = l; } @Override protected void compute() { if ((indexLast - indexStart) > THRESHOLD) for (int i = indexStart; i < indexLast; i++) numbers [i] = numbers [i] + Math.random(); else invokeAll (new CustomRecursiveAction(numbers, indexStart, (indexStart - indexLast) / 2), new CustomRecursiveAction(numbers, (indexStart - indexLast) / 2, indexLast)); } } package org.mano.example; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) { final int SIZE = 10; ForkJoinPool pool = new ForkJoinPool(); double na[] = new double [SIZE]; System.out.println("initialized random values :"); for (int i = 0; i < na.length; i++) { na[i] = (double) i + Math.random(); System.out.format("%.4f ", na[i]); } System.out.println(); CustomRecursiveAction task = new CustomRecursiveAction(na, 0, na.length); pool.invoke(task); System.out.println("Changed values :"); for (inti = 0; i < 10; i++) System.out.format("%.4f ", na[i]); System.out.println(); } }
निष्कर्ष
यह समानांतर प्रोग्रामिंग का संक्षिप्त विवरण है और यह जावा में कैसे समर्थित है। यह एक अच्छी तरह से स्थापित तथ्य है कि N . होना कोर सब कुछ नहीं बनाने जा रहा है N गुना तेज। जावा अनुप्रयोगों का केवल एक वर्ग ही इस सुविधा का प्रभावी ढंग से उपयोग करता है। समानांतर प्रोग्रामिंग कोड एक कठिन फ्रेम है। इसके अलावा, प्रभावी समानांतर कार्यक्रमों को लोड संतुलन, समानांतर कार्यों के बीच संचार, और इसी तरह के मुद्दों पर विचार करना चाहिए। कुछ एल्गोरिदम हैं जो समानांतर निष्पादन के लिए बेहतर हैं लेकिन कई नहीं हैं। किसी भी मामले में, जावा एपीआई इसके समर्थन से कम नहीं है। हम हमेशा एपीआई के साथ छेड़छाड़ कर सकते हैं ताकि यह पता लगाया जा सके कि सबसे अच्छा क्या है। हैप्पी कोडिंग 🙂