थ्रेड पूल का उपयोग कब किया जाता है?


104

इसलिए मुझे इस बात की समझ है कि Node.js कैसे काम करता है: इसके पास एक एकल श्रोता धागा है जो एक घटना प्राप्त करता है और फिर इसे एक कार्यकर्ता पूल को सौंपता है। एक बार काम पूरा करने के बाद कार्यकर्ता थ्रेड श्रोता को सूचित करता है, और श्रोता फिर कॉल करने वाले को प्रतिक्रिया देता है।

मेरा प्रश्न यह है: यदि मैं Node.js में एक HTTP सर्वर को खड़ा करता हूं और अपने किसी रूट किए गए ईवेंट (जैसे "/ परीक्षण / नींद") पर नींद को बुलाता हूं, तो पूरी प्रणाली रुक जाती है। यहां तक ​​कि एकल श्रोता धागा। लेकिन मेरी समझ यह थी कि यह कोड कार्यकर्ता पूल पर हो रहा है।

अब, इसके विपरीत, जब मैं MongoDB से बात करने के लिए Mongoose का उपयोग करता हूं, DB पढ़ता है एक महंगा I / O ऑपरेशन। नोड काम को एक धागे में सौंपने और कॉलबैक प्राप्त करने में सक्षम होने में सक्षम लगता है; DB से लोड होने में लगने वाला समय सिस्टम को ब्लॉक नहीं करता है।

Node.js श्रोता धागे बनाम थ्रेड पूल थ्रेड का उपयोग करने का निर्णय कैसे लेता है? मैं इवेंट कोड क्यों नहीं लिख सकता जो सोता है और केवल एक थ्रेड पूल थ्रेड को ब्लॉक करता है?


@ तोबी - मैंने वो देखा है। यह अभी भी मेरे सवाल का जवाब नहीं देता है। यदि काम दूसरे धागे पर होता, तो नींद केवल उस धागे को प्रभावित करती है, न कि सुनने वाले को।
हैनी

8
एक वास्तविक प्रश्न, जहां आप अपने आप से कुछ समझने की कोशिश करते हैं, और जब आप भूलभुलैया से बाहर नहीं निकल पाते हैं, तो आप मदद मांगते हैं।
राफेल Eyng

जवाबों:


240

नोड कैसे काम करता है इसकी आपकी समझ सही नहीं है ... लेकिन यह एक आम गलत धारणा है, क्योंकि स्थिति की वास्तविकता वास्तव में काफी जटिल है, और आम तौर पर "नोड सिंगल थ्रेडेड" जैसे छोटे शब्दों के लिए उकसाया जाता है जो चीजों को सरल बनाते हैं ।

फिलहाल, हम क्लस्टर और वेबवर्क-थ्रेड्स के माध्यम से स्पष्ट मल्टी-प्रोसेसिंग / मल्टी-थ्रेडिंग को अनदेखा करेंगे , और केवल विशिष्ट गैर-थ्रेडेड नोड के बारे में बात करेंगे।

नोड एक ईवेंट लूप में चलता है। यह सिंगल थ्रेडेड है, और आपको केवल एक ही धागा मिलता है। आपके द्वारा लिखी गई सभी जावास्क्रिप्ट इस लूप में निष्पादित होती है, और यदि उस कोड में एक ब्लॉकिंग ऑपरेशन होता है, तो यह पूरे लूप को ब्लॉक कर देगा और इसके खत्म होने तक कुछ और नहीं होगा। यह नोड का आमतौर पर एकल थ्रेडेड प्रकृति है जिसके बारे में आप बहुत सुनते हैं। लेकिन, यह पूरी तस्वीर नहीं है।

कुछ फ़ंक्शन और मॉड्यूल, आमतौर पर C / C ++ में लिखे जाते हैं, अतुल्यकालिक I / O का समर्थन करते हैं। जब आप इन फ़ंक्शन और विधियों को कॉल करते हैं, तो वे आंतरिक रूप से एक कार्यकर्ता थ्रेड पर कॉल पास करने का प्रबंधन करते हैं। उदाहरण के लिए, जब आप fsकिसी फ़ाइल का अनुरोध करने के लिए मॉड्यूल का उपयोग करते हैं , तो fsमॉड्यूल उस कॉल को एक श्रमिक थ्रेड पर भेजता है, और वह कार्यकर्ता इसकी प्रतिक्रिया की प्रतीक्षा करता है, जो तब इवेंट लूप को वापस प्रस्तुत करता है जो उस पर बिना मंथन किए हुए है। इस बीच। यह सब आप से दूर है, नोड डेवलपर, और इसमें से कुछ को मॉड्यूल डेवलपर्स से कामेच्छा के उपयोग से दूर रखा गया है

जैसा कि डेनिस डॉलफस ने टिप्पणियों में ( इसी तरह के एक प्रश्न के उत्तर से) बताया है, लिब्यू द्वारा अतुल्यकालिक I / O प्राप्त करने के लिए उपयोग की जाने वाली रणनीति हमेशा एक थ्रेड पूल नहीं होती है, विशेष रूप से httpमॉड्यूल के मामले में एक अलग रणनीति प्रतीत होती है। इस समय उपयोग किया जाता है। हमारे उद्देश्यों के लिए यह ध्यान रखना मुख्य रूप से महत्वपूर्ण है कि अतुल्यकालिक संदर्भ कैसे प्राप्त किया जाता है (libuv का उपयोग करके) और यह कि libuv द्वारा अनुरक्षित थ्रेड पूल उस पुस्तकालय द्वारा अतुल्यकालिकता को प्राप्त करने के लिए प्रस्तावित कई रणनीतियों में से एक है।


ज्यादातर संबंधित स्पर्शरेखा पर, इस उत्कृष्ट लेख में नोड असिंक्रोनसिटी, और कुछ संबंधित संभावित समस्याओं और उनसे निपटने के तरीके को प्राप्त करने के तरीके का बहुत गहरा विश्लेषण है । इसमें से अधिकांश का विस्तार मैंने जो लिखा है, उस पर किया है, लेकिन इसके अतिरिक्त यह इंगित करता है:

  • कोई भी बाहरी मॉड्यूल जो आप अपनी परियोजना में शामिल करते हैं, जो मूल C ++ का उपयोग करता है और libuv थ्रेड पूल का उपयोग करने की संभावना है (सोचें: डेटाबेस विकल्प)
  • libuv में डिफ़ॉल्ट थ्रेड पूल का आकार 4 है, और थ्रेड पूल तक पहुंच का प्रबंधन करने के लिए एक कतार का उपयोग करता है - अपशॉट यह है कि यदि आपके पास एक ही समय में 5 लंबे समय से चल रहे DB प्रश्न हैं, तो उनमें से एक (और कोई अन्य अतुल्यकालिक कार्रवाई जो कि थ्रेड पूल पर निर्भर करती है) उन प्रश्नों के समाप्त होने से पहले ही शुरू होने का इंतजार कर रही होगी
  • आप UV_THREADPOOL_SIZEपर्यावरण चर के माध्यम से थ्रेड पूल का आकार बढ़ाकर इसे कम कर सकते हैं , इसलिए जब तक आप थ्रेड पूल बनाने और बनाने से पहले इसे करते हैं:process.env.UV_THREADPOOL_SIZE = 10;

आप नोड में पारंपरिक बहु प्रसंस्करण या बहु सूत्रण चाहते हैं, आप में बनाया के माध्यम से प्राप्त कर सकते हैं clusterइस तरह के ऊपर उल्लिखित के रूप में मॉड्यूल या अन्य विभिन्न मॉड्यूल webworker-threads, या आपने अपने कार्य का बेडौल की किसी तरह से लागू करने और मैन्युअल रूप से का उपयोग करके नकली यह कर सकते हैं setTimeoutया setImmediateया process.nextTickअपने काम को रोकने के लिए और बाद की लूप में इसे जारी रखें ताकि अन्य प्रक्रियाएं पूरी हो सकें (लेकिन यह अनुशंसित नहीं है)।

कृपया ध्यान दें, यदि आप जावास्क्रिप्ट में लंबे समय तक चलने / अवरुद्ध कोड लिख रहे हैं, तो आप शायद गलती कर रहे हैं। अन्य भाषाएं अधिक कुशलता से प्रदर्शन करेंगी।


1
पवित्र बकवास, यह पूरी तरह से मेरे लिए इसे साफ करता है। थैंक यू सो मच @ जसन!
हैनी

5
कोई समस्या नहीं है :) मैंने खुद को पाया कि आप बहुत लंबे समय से पहले नहीं हैं, और एक अच्छी तरह से परिभाषित उत्तर में आना कठिन था क्योंकि एक तरफ आपके पास C / C ++ देवता हैं जिनके लिए उत्तर स्पष्ट है, और दूसरी तरफ आपके पास विशिष्ट है वेब देवता जिन्होंने पहले इस प्रकार के प्रश्नों को बहुत गहराई से नहीं जाना है। मुझे यकीन नहीं है कि मेरा जवाब तकनीकी रूप से सही है जब आप सी स्तर पर उतरते हैं, लेकिन व्यापक स्ट्रोक में यह सही है।
जेसन

3
नेटवर्क अनुरोधों के लिए थ्रेड पूल का उपयोग करना एक विशाल संसाधन अपशिष्ट होगा। इस सवाल के अनुसार "यह async नेटवर्क I / O पर आधारित है, async I / O इंटरफेस के आधार पर विभिन्न प्लेटफार्मों, जैसे कि एपोल, केक्यू और IOCP, थ्रेड पूल के बिना" - जो समझ में आता है।
डेनिस डॉलफस

1
... उस ने कहा, यदि आप सीधे मुख्य जावास्क्रिप्ट थ्रेड में कुछ भारी लिफ्टिंग करते हैं, या आपके पास पर्याप्त संसाधन नहीं हैं या आप थ्रेडपूल के लिए पर्याप्त हेडरूम देने के लिए उन्हें उचित रूप से प्रबंधित नहीं करते हैं, तो आप कम संगति में अंतराल का परिचय दे सकते हैं थ्रेसहोल्ड - अपशॉट यह है कि समान सिस्टम संसाधनों के लिए, आप आमतौर पर नोड के साथ उच्च थ्रूपुट का अनुभव करेंगे। अन्य विकल्पों की तुलना में (हालांकि अन्य भाषा में अन्य इवेंट-आधारित सिस्टम हैं जो चुनौती देने का लक्ष्य रखते हैं - जो मैंने नहीं किया है हालांकि हाल ही के बेंचमार्क देखे) - यह स्पष्ट है कि एक घटना आधारित मॉडल एक थ्रेडेड मॉडल को बेहतर बनाता है।
जेसन

1
@Aabid श्रोता धागा डेटाबेस क्वेरी को निष्पादित नहीं करता है, इसलिए इसे उन सभी 10 प्रश्नों के लिए लगभग 6 सेकंड का समय लगेगा (4 के डिफ़ॉल्ट थ्रेड पूल आकार द्वारा)। यदि आपको किसी ऐसे कार्य को जावास्क्रिप्ट में करने की आवश्यकता है जिसे पूरा करने के लिए उस डेटाबेस क्वेरी के परिणामों की आवश्यकता नहीं है, जैसे कि अधिक अनुरोध आते हैं, तो थ्रेड पूल द्वारा किसी भी अतुल्यकालिक कार्य को पूरा करने की आवश्यकता नहीं होती है, यह मुख्य में काम करना जारी रखेगा घटना पाश।
जेसन

20

इसलिए मुझे इस बात की समझ है कि Node.js कैसे काम करता है: इसके पास एक एकल श्रोता धागा है जो एक घटना प्राप्त करता है और फिर इसे एक कार्यकर्ता पूल को सौंपता है। एक बार काम पूरा करने के बाद कार्यकर्ता थ्रेड श्रोता को सूचित करता है, और श्रोता फिर कॉल करने वाले को प्रतिक्रिया देता है।

यह वास्तव में सही नहीं है। Node.js के पास केवल एक "कार्यकर्ता" धागा है जो जावास्क्रिप्ट निष्पादन करता है। नोड के भीतर थ्रेड होते हैं जो आईओ प्रसंस्करण को संभालते हैं, लेकिन उन्हें "श्रमिक" के रूप में सोचना एक गलत धारणा है। वहाँ वास्तव में सिर्फ IO हैंडलिंग और नोड के आंतरिक कार्यान्वयन के कुछ अन्य विवरण हैं, लेकिन एक प्रोग्रामर के रूप में आप कुछ बिस्कुट जैसे MAX_LISTENERS के अलावा उनके व्यवहार को प्रभावित नहीं कर सकते हैं।

मेरा प्रश्न यह है: यदि मैं Node.js में एक HTTP सर्वर को खड़ा करता हूं और अपने किसी रूट किए गए ईवेंट (जैसे "/ परीक्षण / नींद") पर नींद को बुलाता हूं, तो पूरी प्रणाली रुक जाती है। यहां तक ​​कि एकल श्रोता धागा। लेकिन मेरी समझ यह थी कि यह कोड कार्यकर्ता पूल पर हो रहा है।

जावास्क्रिप्ट में कोई नींद तंत्र नहीं है। हम इस पर और अधिक चर्चा कर सकते हैं यदि आप एक कोड स्निपेट पोस्ट करते हैं जो आपको लगता है कि "नींद" का अर्थ है। time.sleep(30)उदाहरण के लिए, अजगर में कुछ पसंद करने के लिए कॉल करने के लिए ऐसा कोई फ़ंक्शन नहीं है । setTimeoutलेकिन वहाँ है कि मौलिक रूप से सो नहीं है। setTimeoutऔर setIntervalस्पष्ट रूप से रिलीज , ब्लॉक नहीं, कोड के अन्य बिट्स इवेंट लूप मुख्य निष्पादन थ्रेड पर निष्पादित कर सकते हैं। केवल एक चीज जो आप कर सकते हैं वह है व्यस्त लूप CPU को इन-मेमोरी कम्प्यूटेशन के साथ, जो वास्तव में मुख्य निष्पादन थ्रेड को भूखा रखेगा और आपके प्रोग्राम को अप्रतिसादी करेगा।

Node.js श्रोता धागे बनाम थ्रेड पूल थ्रेड का उपयोग करने का निर्णय कैसे लेता है? मैं इवेंट कोड क्यों नहीं लिख सकता जो सोता है और केवल एक थ्रेड पूल थ्रेड को ब्लॉक करता है?

नेटवर्क IO हमेशा एसिंक्रोनस होता है। कहानी का अंत। डिस्क IO में सिंक्रोनस और एसिंक्रोनस दोनों API हैं, इसलिए कोई "निर्णय" नहीं है। नोड.जेएस एपीआई कोर कार्यों के अनुसार व्यवहार करेगा जिसे आप सिंक बनाम सामान्य एसिंक्स कहते हैं। उदाहरण के लिए: fs.readFileबनाम fs.readFileSync। बाल प्रक्रियाओं के लिए, अलग child_process.execऔर child_process.execSyncएपीआई भी हैं।

अंगूठे का नियम हमेशा अतुल्यकालिक एपीआई का उपयोग करें। सिंक APIs का उपयोग करने के वैध कारण कनेक्शन नेटवर्क या कनेक्शनों के लिए सुनने से पहले नेटवर्क सेवा में इनिशियलाइज़ेशन कोड के लिए हैं जो बिल्ड टूल्स और इस तरह की चीज़ों के लिए नेटवर्क अनुरोध स्वीकार नहीं करते हैं।


1
ये अतुल्यकालिक एपीआई कहां से आ रहे हैं? मुझे वही मिल रहा है जो आप कह रहे हैं, लेकिन जिसने भी यह API लिखा है, वह IOCP / async में शामिल है। उन्होंने ऐसा करने के लिए कैसे चुना?
हैनी

3
उनका सवाल है कि वह अपने समय के गहन कोड को कैसे लिखेंगे और ब्लॉक नहीं करेंगे।
जेसन

1
हाँ। नोड बुनियादी यूडीपी, टीसीपी और HTTP नेटवर्किंग प्रदान करता है। यह केवल अतुल्यकालिक "पूल-आधारित" एपीआई प्रदान करता है। बिना अपवाद के दुनिया में सभी नोड.जेएस कोड इन पूल-आधारित अतुल्यकालिक एपीआई का उपयोग करते हैं क्योंकि बस सभी उपलब्ध हैं। फाइलसिस्टम और चाइल्ड प्रोसेस एक अलग कहानी है, लेकिन नेटवर्किंग लगातार अतुल्यकालिक है।
पीटर लियोंस

4
सावधान, पीटर, ऐसा न हो कि तुम उसके केतली में लौकिक बर्तन हो। वह जानना चाहता है कि नेटवर्क एपीआई के लेखकों ने यह कैसे किया, न कि कैसे लोग जो नेटवर्क एपीआई का उपयोग करते हैं। मुझे अंततः इस बात की समझ प्राप्त हुई कि नोड फिर से कैसे व्यवहार करता है: गैर-अवरुद्ध घटनाएं क्योंकि मैं अपना स्वयं का गैर-अवरोधक कोड लिखना चाहता था जिसका नेटवर्किंग या अतुल्यकालिक एपीआई में निर्मित किसी भी अन्य से कोई लेना-देना नहीं है। यह स्पष्ट है कि डेविड ऐसा ही करना चाहता है।
जेसन

2
नोड IO के लिए थ्रेड पूल का उपयोग नहीं करता है, यह देशी गैर-अवरुद्ध IO का उपयोग करता है, एकमात्र अपवाद है fs, जहाँ तक मुझे पता है
vkurchatkin

2

थ्रेड पूल कब और किसने इस्तेमाल किया:

जब हम किसी कंप्यूटर पर नोड का उपयोग / स्थापित करते हैं तो सबसे पहले, यह अन्य प्रक्रियाओं के बीच एक प्रक्रिया शुरू करता है जिसे कंप्यूटर में नोड प्रक्रिया कहा जाता है, और यह तब तक चलता रहता है जब तक आप इसे मार नहीं देते। और यह चलने की प्रक्रिया हमारा तथाकथित एकल धागा है।

यहां छवि विवरण दर्ज करें

तो एकल थ्रेड का तंत्र एक नोड एप्लिकेशन को ब्लॉक करना आसान बनाता है लेकिन यह उन विशिष्ट विशेषताओं में से एक है जो Node.js तालिका में लाता है। इसलिए, यदि आप अपना नोड एप्लिकेशन चलाते हैं, तो यह केवल एक ही थ्रेड में चलेगा। कोई बात नहीं अगर आपके पास 1 या दस लाख उपयोगकर्ता एक ही समय में आपके एप्लिकेशन को एक्सेस कर रहे हैं।

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

उसके बाद, सभी मॉड्यूल कोड निष्पादित किए गए फिर सभी कॉलबैक को पंजीकृत करें, आखिरकार, आपके आवेदन के लिए इवेंट लूप शुरू हो गया।

यहां छवि विवरण दर्ज करें

तो जैसा कि हम सभी कॉलबैक फ़ंक्शन से पहले चर्चा करते हैं और उन फ़ंक्शन के अंदर कोड इवेंट लूप के तहत निष्पादित करेंगे। ईवेंट लूप में, लोड विभिन्न चरणों में वितरित किए जाते हैं। वैसे भी, मैं यहाँ इवेंट लूप के बारे में चर्चा नहीं करने जा रहा हूँ।

अच्छी तरह से थ्रेड पूल की बेहतर समझ की खातिर मैं आपसे एक कल्पना करने का अनुरोध करता हूं कि इवेंट लूप में, एक कॉलबैक फ़ंक्शन के अंदर कोड किसी अन्य कॉलबैक फ़ंक्शन के अंदर कोड्स को पूरा करने के बाद निष्पादित होते हैं, अब अगर कुछ कार्य वास्तव में बहुत भारी हैं। वे फिर हमारे नोडज एकल धागे को अवरुद्ध करेंगे। और इसलिए, यह वह जगह है जहां थ्रेड पूल आता है, जो कि इवेंट लूप की तरह है, लिबव लाइब्रेरी द्वारा Node.js को प्रदान किया जाता है।

तो थ्रेड पूल खुद नोड्ज का हिस्सा नहीं है, यह लिबव द्वारा भारी शुल्क को ऑफलोड करने के लिए लिबव द्वारा प्रदान किया गया है, और लिबव उन कोड को अपने स्वयं के थ्रेड्स में निष्पादित करेगा और निष्पादन के बाद लिबुव परिणाम को लूप में घटना में वापस कर देगा।

यहां छवि विवरण दर्ज करें

थ्रेड पूल हमें चार अतिरिक्त धागे देता है, जो मुख्य एकल धागे से पूरी तरह से अलग हैं। और हम वास्तव में इसे 128 थ्रेड तक कॉन्फ़िगर कर सकते हैं।

इसलिए इन सभी धागों ने मिलकर एक थ्रेड पूल का निर्माण किया। और इवेंट लूप तब थ्रेड पूल के लिए भारी कार्यों को स्वचालित रूप से बंद कर सकता है।

मजेदार बात यह है कि यह सब पर्दे के पीछे स्वचालित रूप से होता है। यह हमारे डेवलपर्स नहीं हैं जो तय करते हैं कि थ्रेड पूल में क्या जाता है और क्या नहीं।

कई कार्य थ्रेड पूल में जाते हैं, जैसे कि

-> All operations dealing with files
->Everyting is related to cryptography, like caching passwords.
->All compression stuff
->DNS lookups

0

यह गलतफहमी केवल पूर्व-खाली मल्टी-टास्किंग और सहकारी मल्टीटास्किंग के बीच का अंतर है ...

नींद पूरी कार्निवल को बंद कर देती है क्योंकि सभी सवारी के लिए वास्तव में एक लाइन है, और आपने गेट बंद कर दिया है। इसे "एक जेएस दुभाषिया और कुछ अन्य चीजें" के रूप में सोचें और धागे की अनदेखी करें ... आपके लिए, केवल एक धागा है ...

... तो इसे ब्लॉक न करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.