यदि आपको यह प्रश्न पूछना है तो आप शायद इस बात से अपरिचित हैं कि अधिकांश वेब एप्लिकेशन / सेवाएं क्या करते हैं। आप शायद सोच रहे हैं कि सभी सॉफ्टवेयर ऐसा करते हैं:
user do an action
│
v
application start processing action
└──> loop ...
└──> busy processing
end loop
└──> send result to user
हालाँकि, यह नहीं है कि वेब अनुप्रयोग, या बैक-एंड के रूप में डेटाबेस के साथ वास्तव में कोई भी अनुप्रयोग कैसे काम करता है। वेब ऐप्स ऐसा करते हैं:
user do an action
│
v
application start processing action
└──> make database request
└──> do nothing until request completes
request complete
└──> send result to user
इस परिदृश्य में, सॉफ़्टवेयर अपने चल रहे अधिकांश समय को 0% CPU समय का उपयोग करके डेटाबेस के वापस लौटने के लिए प्रतीक्षा कर रहा है।
बहुस्तरीय नेटवर्क ऐप:
मल्टीथ्रेडेड नेटवर्क ऐप इस तरह उपरोक्त वर्कलोड को संभालते हैं:
request ──> spawn thread
└──> wait for database request
└──> answer request
request ──> spawn thread
└──> wait for database request
└──> answer request
request ──> spawn thread
└──> wait for database request
└──> answer request
इसलिए थ्रेड अपना ज्यादातर समय 0% CPU का उपयोग करके डेटा के वापस आने के लिए डेटाबेस के इंतजार में बिताते हैं। ऐसा करते समय उन्हें एक थ्रेड के लिए आवश्यक मेमोरी आवंटित करनी होती है, जिसमें प्रत्येक थ्रेड आदि के लिए एक पूरी तरह से अलग प्रोग्राम स्टैक शामिल होता है। इसके अलावा, उन्हें एक थ्रेड शुरू करना होगा, जो उतना महंगा नहीं है, जितना एक फुल प्रोसेस शुरू करना अभी भी ठीक नहीं है सस्ता।
सिंगलथ्रेड इवेंट लूप
चूँकि हम अपना अधिकांश समय 0% CPU का उपयोग करते हैं, इसलिए जब हम CPU का उपयोग नहीं कर रहे हैं तो कुछ कोड क्यों नहीं चलाते हैं? इस तरह, प्रत्येक अनुरोध को अभी भी बहु-स्तरीय अनुप्रयोगों के रूप में सीपीयू समय की एक ही राशि मिलेगी, लेकिन हमें एक धागा शुरू करने की आवश्यकता नहीं है। तो हम यह करते हैं:
request ──> make database request
request ──> make database request
request ──> make database request
database request complete ──> send response
database request complete ──> send response
database request complete ──> send response
व्यवहार में दोनों दृष्टिकोण लगभग एक ही विलंबता के साथ रिटर्न डेटा है क्योंकि यह डेटाबेस प्रतिक्रिया समय है जो प्रसंस्करण पर हावी है।
यहाँ मुख्य लाभ यह है कि हमें एक नए धागे की आवश्यकता नहीं है, इसलिए हमें बहुत सारे और बहुत सारे मॉलोक करने की ज़रूरत नहीं है जो हमें धीमा कर देगा।
जादू, अदृश्य थ्रेडिंग
प्रतीत होता है रहस्यमय बात यह है कि उपरोक्त दोनों दृष्टिकोण "समानांतर" में कार्यभार चलाने के लिए कैसे प्रबंधित करते हैं? इसका उत्तर यह है कि डेटाबेस थ्रेडेड है। इसलिए हमारा एकल-थ्रेडेड ऐप वास्तव में एक और प्रक्रिया के बहु-थ्रेडेड व्यवहार का लाभ उठा रहा है: डेटाबेस।
जहां सिंगलथ्रेड अप्रोच विफल रहता है
यदि डेटा वापस करने से पहले आपको बहुत सारे CPU गणना करने की आवश्यकता होती है, तो एक एकलथ्रेड ऐप बड़ा विफल हो जाता है। अब, मैं डेटाबेस परिणाम के लिए लूप प्रसंस्करण के लिए मतलब नहीं है। वह अभी भी ज्यादातर O (n) है। मेरा मतलब है कि फूरियर ट्रांसफॉर्म करने (उदाहरण के लिए एमपी 3 एन्कोडिंग), रे ट्रेसिंग (3 डी रेंडरिंग) आदि जैसी चीजें हैं।
सिंगलथ्रेड एप्स का एक और नुकसान यह है कि यह केवल सिंगल सीपीयू कोर का उपयोग करेगा। इसलिए यदि आपके पास क्वाड-कोर सर्वर है (असामान्य नहीं) तो आप अन्य 3 कोर का उपयोग नहीं कर रहे हैं।
जहां बहुस्तरीय दृष्टिकोण विफल हो जाता है
यदि आप प्रति थ्रेड RAM बहुत आवंटित करने की आवश्यकता है, तो एक multithreaded एप्लिकेशन बड़ा विफल रहता है। सबसे पहले, रैम उपयोग का मतलब है कि आप एक एकल ऐप के रूप में कई अनुरोधों को संभाल नहीं सकते हैं। इससे भी बदतर, मलोच धीमा है। बहुत सारी और बहुत सी वस्तुओं को आवंटित करना (जो कि आधुनिक वेब फ्रेमवर्क के लिए सामान्य है) का मतलब है कि हम संभावित रूप से सिंगलथ्रेड एप्स की तुलना में धीमी गति से समाप्त हो सकते हैं। यह वह जगह है जहाँ नोड.जेएस आमतौर पर जीतते हैं।
एक उपयोग-मामला जो मल्टीथ्रेड को बदतर बनाने का अंत करता है, जब आपको अपने थ्रेड में एक और स्क्रिप्टिंग भाषा चलाने की आवश्यकता होती है। पहले आपको आम तौर पर उस भाषा के लिए पूरे रनटाइम को मॉलॉक करने की आवश्यकता होती है, फिर आपको अपनी स्क्रिप्ट द्वारा उपयोग किए जाने वाले चर को मॉलॉक करने की आवश्यकता होती है।
इसलिए यदि आप सी या गो या जावा में नेटवर्क ऐप लिख रहे हैं तो थ्रेडिंग का ओवरहेड आमतौर पर बहुत बुरा नहीं होगा। यदि आप PHP या रूबी की सेवा के लिए एक सी वेब सर्वर लिख रहे हैं तो जावास्क्रिप्ट या रूबी या पायथन में एक तेज़ सर्वर लिखना बहुत आसान है।
हाइब्रिड दृष्टिकोण
कुछ वेब सर्वर एक हाइब्रिड दृष्टिकोण का उपयोग करते हैं। उदाहरण के लिए Nginx और Apache2 इवेंट लूप के थ्रेड पूल के रूप में अपने नेटवर्क प्रोसेसिंग कोड को लागू करते हैं। प्रत्येक थ्रेड इवेंट लूप चलाता है एक साथ प्रसंस्करण एकल-थ्रेडेड अनुरोध करता है, लेकिन अनुरोध कई थ्रेड्स के बीच लोड-संतुलित हैं।
कुछ एकल-थ्रेडेड आर्किटेक्चर भी हाइब्रिड दृष्टिकोण का उपयोग करते हैं। एक प्रक्रिया से कई थ्रेड लॉन्च करने के बजाय आप कई एप्लिकेशन लॉन्च कर सकते हैं - उदाहरण के लिए, क्वाड-कोर मशीन पर 4 नोड। जेएस सर्वर। फिर आप प्रक्रियाओं के बीच काम का बोझ फैलाने के लिए एक लोड बैलेंसर का उपयोग करते हैं।
प्रभाव में दो दृष्टिकोण एक दूसरे के तकनीकी रूप से समान दर्पण-चित्र हैं।