फिक्स्ड थ्रेडपूल बनाम कैश्ड थ्रेडपूल: दो बुराइयों का कम


94

मेरे पास एक कार्यक्रम है जो थ्रेड्स को फैलाता है (~ 5-150) जो कार्यों का एक गुच्छा प्रदर्शन करते हैं। मूल रूप से, मैंने इसका उपयोग किया FixedThreadPoolक्योंकि इस तरह के एक प्रश्न ने सुझाव दिया कि वे लंबे समय तक जीवित कार्यों के लिए बेहतर अनुकूल थे और मेरीथ्रेडिंग के बहुत सीमित ज्ञान के साथ, मैंने थ्रेड्स के औसत जीवन (कई मिनट) को " लंबे समय तक जीवित " माना ।

हालाँकि, मैंने हाल ही में अतिरिक्त थ्रेड्स को फैलाने की क्षमता को जोड़ा और ऐसा करने से मुझे मेरे द्वारा निर्धारित थ्रेड लिमिट से ऊपर ले जाता है। इस मामले में, क्या मैं उन थ्रेड्स की संख्या का अनुमान लगा सकता हूं या बढ़ा सकता CachedThreadPoolहूं, जिनकी मैं अनुमति दे सकता हूं या स्विच कर सकता हूं।

उन दोनों को पूरी तरह से बाहर करने की कोशिश करना, कोई अंतर नहीं लगता है इसलिए मैं CachedThreadPoolबर्बादी से बचने के लिए बस साथ जाने के लिए इच्छुक हूं । हालाँकि, क्या थ्रेड्स के जीवन काल का मतलब है कि मुझे इसके बजाय ए FixedThreadPoolऔर अप्रयुक्त थ्रेड्स से निपटना चाहिए ? यह प्रश्न ऐसा लगता है जैसे उन अतिरिक्त धागों को बर्बाद नहीं किया गया है लेकिन मैं स्पष्टीकरण की सराहना करूंगा।

जवाबों:


108

कैश्ड थ्रेडपूल ठीक वही है जो आपको अपनी स्थिति के लिए उपयोग करना चाहिए क्योंकि लंबे समय तक चलने वाले थ्रेड्स के लिए एक का उपयोग करने के लिए कोई नकारात्मक परिणाम नहीं हैं। कैश्ड थ्रेड्स के बारे में जावा डॉक में टिप्पणी केवल छोटे कार्यों के लिए उपयुक्त होने का सुझाव देती है कि वे ऐसे मामलों के लिए विशेष रूप से उपयुक्त हैं, यह नहीं कि उन्हें लंबे समय तक चलने वाले कार्यों में शामिल नहीं किया जाना चाहिए या नहीं।

आगे विस्तार करने के लिए, Executors.newCachedThreadPool और Executors.newFixedThreadPool दोनों एक ही थ्रेड पूल कार्यान्वयन (कम से कम खुले JDK में) अलग-अलग मापदंडों के साथ समर्थित हैं। अंतर केवल उनके धागे न्यूनतम, अधिकतम, थ्रेड मार समय और कतार प्रकार के होते हैं।

public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>());
 }

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                 60L, TimeUnit.SECONDS,
                                 new SynchronousQueue<Runnable>());
}

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

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


1
"कैश्ड थ्रेडपूल ठीक वही है जो आपको अपनी स्थिति के लिए उपयोग करना चाहिए क्योंकि लंबे समय तक चलने वाले थ्रेड्स के लिए एक का उपयोग करने के लिए कोई नकारात्मक परिणाम नहीं हैं"। मुझे नहीं लगता कि मैं सहमत हूं। कैश्ड थ्रेडपूल गतिशील रूप से बिना किसी ऊपरी सीमा के धागे बनाता है। बड़ी संख्या में थ्रेड्स पर लंबे समय तक चलने वाले कार्य संभावित रूप से सभी संसाधनों को रोक सकते हैं। इसके अलावा, आदर्श से अधिक थ्रेड्स होने से इन थ्रेड्स के संदर्भ स्विचिंग पर बहुत सारे संसाधन बर्बाद हो सकते हैं। यद्यपि आपने उत्तर के अंत में समझाया कि कस्टम थ्रॉटलिंग की आवश्यकता है, उत्तर की शुरुआत थोड़ा भ्रामक है।
निशीत

1
क्यों नहीं बस एक ThreadPoolExecutorतरह से बना ThreadPoolExecutor(0, maximumPoolSize, 60L, TimeUnit.SECONDS, SynchronousQueue())?
अभिजीत सरकार

45

दोनों FixedThreadPoolऔर CachedThreadPoolअत्यधिक लोड अनुप्रयोगों में बुराइयों कर रहे हैं।

CachedThreadPool से ज्यादा खतरनाक है FixedThreadPool

यदि आपका आवेदन अत्यधिक भरा हुआ है और कम विलंबता की मांग करता है, तो कमियों के कारण दोनों विकल्पों से छुटकारा पाने के लिए बेहतर है

  1. कार्य कतार की असंबद्ध प्रकृति: यह स्मृति या उच्च विलंबता के कारण हो सकती है
  2. CachedThreadPoolथ्रेड निर्माण पर लंबे समय तक चलने वाले धागे नियंत्रण से बाहर हो जाएंगे

चूँकि आप जानते हैं कि दोनों ही बुराइयाँ हैं, इसलिए कम बुराई अच्छा नहीं करती। थ्रेडपूल एक्सक्यूजर को प्राथमिकता दें , जो कई मापदंडों पर दानेदार नियंत्रण प्रदान करता है।

  1. बेहतर नियंत्रण के लिए बाउंड कतार के रूप में कार्य कतार निर्धारित करें
  2. राइट रिजेक्शनहैंडलर लें - आपका खुद का रिजेक्शनहैंडलर या JDK द्वारा प्रदान किया गया डिफॉल्ट हैंडलर
  3. यदि आपको कार्य पूरा होने से पहले / बाद में कुछ करना है, तो ओवरराइड करें beforeExecute(Thread, Runnable)औरafterExecute(Runnable, Throwable)
  4. यदि थ्रेड कस्टमाइज़ेशन आवश्यक है, तो थ्रेडफ्रीक्शन ओवरराइड करें
  5. नियंत्रण थ्रेड पूल का आकार गतिशील रूप से रन टाइम (संबंधित एसई प्रश्न: डायनेमिक थ्रेड पूल )

यदि कोई व्यक्ति कॉमनपूल का उपयोग करने का निर्णय लेता है तो क्या होगा?
क्रॉस्क कूल

1
@ रवींद्र - आपने कैश्ड थ्रेडपूल और फिक्स्डह्रेडपूल दोनों की शान को खूबसूरती से समझाया है। इससे पता चलता है कि आपको कॉन्सटेबल पैकेज की गहरी समझ मिल गई है।
अय्याक जूल

5

इसलिए मेरे पास एक कार्यक्रम है जो थ्रेड्स (~ 5-150) को जन्म देता है जो कार्यों का एक गुच्छा प्रदर्शन करते हैं।

क्या आप वाकई समझ गए हैं कि वास्तव में आपके ओएस और पसंद के हार्डवेयर द्वारा थ्रेड कैसे संसाधित किए जाते हैं? कैसे जावा ओएस थ्रेड्स को थ्रेड करता है, कैसे सीपीयू थ्रेड्स को थ्रेड मैप करता है? मैं पूछ रहा हूं क्योंकि वन JRE में 150 थ्रेड्स बनाने से केवल तभी समझ में आता है जब आपके पास बड़े पैमाने पर सीपीयू कोर / थ्रेड्स होते हैं, जो कि सबसे अधिक संभावना नहीं है। उपयोग में OS और RAM के आधार पर, n थ्रेड से अधिक बनाने से आपके JRE को OOM त्रुटियों के कारण समाप्त किया जा सकता है। इसलिए आपको थ्रेड्स के बीच वास्तव में अंतर करना चाहिए और उन थ्रेड्स को करने के लिए काम करना चाहिए, आप कितने काम करने में सक्षम हैं आदि।

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

और यह समस्या फिक्स्ड ट्रेडपूल के साथ नहीं होती है, जैसे कि 2 + एन थ्रेड्स के साथ बनाया गया है, जहां एन उचित रूप से कम है, क्योंकि उस हार्डवेयर और ओएस संसाधनों के साथ थ्रेड के प्रबंधन के लिए बहुत कम ओवरहेड का उपयोग किया जाता है जो वैसे भी नहीं चल सकते हैं।


कभी-कभी एक बेहतर विकल्प नहीं होता है, आपके पास बस 1 सीपीयू कोर हो सकता है लेकिन अगर आप एक सर्वर चला रहे हैं जहां हर उपयोगकर्ता अनुरोध अनुरोध को संसाधित करने के लिए एक धागा ट्रिगर करेगा, तो कोई अन्य उचित विकल्प नहीं होगा, खासकर यदि आप योजना बनाते हैं अपना उपयोगकर्ता आधार बढ़ने पर सर्वर को स्केल करने के लिए।
मिशेल फ़िनस्टीन

@mFeinstein यदि किसी के पास थ्रेड पूल कार्यान्वयन को चुनने की स्थिति में नहीं है तो कोई विकल्प कैसे हो सकता है? 1 सीपीयू कोर के साथ आपके उदाहरण में केवल अधिक धागे पैदा करने से कोई मतलब नहीं है, यह फिक्स्डह्रेडपूल का उपयोग करके मेरे उदाहरण के लिए पूरी तरह से फिट है। तराजू आसानी से अच्छी तरह से, पहले या दो कार्यकर्ता धागे के साथ, बाद में कोर की संख्या के आधार पर 10 या 15 के साथ।
थोरस्टन शॉनिंग

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

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

3
@ ThorstenSchöning, 2-कोर मशीन पर 50 सीपीयू-बाउंड थ्रेड्स अनहेल्दी हैं। 2-कोर मशीन पर 50 IO- बाउंड थ्रेड्स होना बहुत मददगार हो सकता है।
पॉल ड्रेपर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.