14

मेरे एंड्रॉइड प्रोजेक्ट में मेरे पास बहुत सारे स्थान थे जहां मुझे कुछ कोड असीमित रूप से चलाने की आवश्यकता है (एक वेब अनुरोध, डीबी आदि को कॉल करें) । यह लंबे समय तक चलने वाले कार्यों (अधिकतम कुछ सेकंड) नहीं है। अब तक मैं एक नया धागा बनाने के साथ इस तरह की चीजें कर रहा था, इसे कार्य के साथ एक नया रननेबल पास कर रहा था। लेकिन हाल ही में मैंने जावा में धागे और समरूपता के बारे में एक लेख पढ़ा है और समझा है कि प्रत्येक कार्य के लिए एक नया थ्रेड बनाना एक अच्छा निर्णय नहीं है।नया थ्रेड (कार्य) .start() एंड्रॉइड में VS ThreadPoolExecutor.submit (कार्य)

तो अब मैंने अपने Application कक्षा में ThreadPoolExecutor बनाया है जिसमें 5 धागे हैं।

public class App extends Application { 

    private ThreadPoolExecutor mPool; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     mPool = (ThreadPoolExecutor)Executors.newFixedThreadPool(5); 
    } 
} 

और यह भी मैं निष्पादक को Runnable कार्य प्रस्तुत करने के लिए एक विधि है:

public void submitRunnableTask(Runnable task){ 
    if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){ 
     mPool.submit(task); 
    } else { 
     new Thread(task).start(); 
    } 
} 

तो जब मैं अपने कोड में एक अतुल्यकालिक काम चलाना चाहते हैं मैं उदाहरण मिल यहाँ कोड है App का और submitRunnableTask पर कॉल करने योग्य विधि को कॉल करें। जैसा कि आप देख सकते हैं, मैं यह भी जांचता हूं कि अगर थ्रेड पूल में मेरे काम को निष्पादित करने के लिए मुफ्त धागे हैं, यदि नहीं, तो मैं एक नया थ्रेड बनाता हूं (मुझे नहीं लगता कि यह होगा, लेकिन किसी भी मामले में ... मैं नहीं करता हूं ' टी मेरे काम को कतार में इंतजार करना और ऐप को धीमा करना चाहते हैं)।

onTerminate एप्लिकेशन के कॉलबैक विधि में मैंने पूल बंद कर दिया।

तो मेरा प्रश्न निम्न है: क्या कोड में नए थ्रेड बनाने के बाद इस तरह का पैटर्न बेहतर है? मेरे नए दृष्टिकोण के पेशेवर और विपक्ष क्या हैं? क्या इससे समस्याएं पैदा हो सकती हैं जिन्हें मैं अभी तक नहीं जानता हूं? क्या आप मेरे एसिंक्रोनस कार्यों को प्रबंधित करने के लिए मुझसे बेहतर कुछ सलाह दे सकते हैं?

पीएस मेरे पास एंड्रॉइड और जावा में कुछ अनुभव है, लेकिन मैं एक समेकन गुरु होने से बहुत दूर हूं) ऐसे में ऐसे पहलू हो सकते हैं जिन्हें मैं इस तरह के प्रश्नों में अच्छी तरह समझ नहीं पा रहा हूं। किसी भी सलाह की सराहना की जाएगी।

+2

एक थ्रेडपूल प्रत्येक नए कार्य के लिए धागे को बनाने और नष्ट करने के काफी ओवरहेड से बचाता है। साथ ही, यह आपको किसी भी प्रकार की पॉलिसी को नियंत्रित करने की अनुमति देता है कि यह किसी भी क्षण में कितने कार्यकर्ता धागे मौजूद है, बस ऐसा होने की बजाय यह होता है। साथ ही, यह आपको पुन: आविष्कार करने वाली मशीनरी से बचाता है ताकि उन्हें बंद कर दिया जा सके यदि ऐसा कुछ है जो आपके आवेदन को करने की ज़रूरत है। –

+1

मैं कार्य समांतर और डेटा समांतर अनुप्रयोगों दोनों के लिए कई खुली स्रोत परियोजनाओं का प्रबंधन करता हूं। यहां एक लेख है जो एंड्रॉइड के लिए काम करता है: http://coopsoft.com/ar/AndroidArticle.html – edharned

+0

@edharned, बहुत बहुत धन्यवाद, लेकिन मेरी पहली छाप यह है कि आपका ढांचा मेरे मामले के लिए बहुत जटिल है।मुझे बस कुछ छोटे JSON-RPC अनुरोध और कुछ डेटाबेस क्वेरीज़ बनाने की आवश्यकता है। हालांकि मैंने विवरण में आपके ढांचे की जांच नहीं की है, और मेरी पहली छाप गलत हो सकती है। – Andranik

उत्तर

19

इस उत्तर मान लिया गया है अपने कार्यों को कम

पैटर्न के इस प्रकार बेहतर तो कोड में नए धागे पैदा कर रही है कर रहे हैं?

यह बेहतर है, लेकिन यह अभी भी आदर्श से बहुत दूर है। आप अभी भी छोटे कार्यों के लिए धागे बना रहे हैं। इसके बजाय आपको केवल एक अलग प्रकार का थ्रेड पूल बनाने की आवश्यकता है - उदाहरण के लिए Executors.newScheduledThreadPool(int corePoolSize)

व्यवहार में क्या अंतर है?

  • एक FixedThreadPool हमेशा उपयोग करने के लिए धागे का एक सेट करना होगा और अगर सब कुछ धागे व्यस्त हैं, एक नया कार्य एक कतार में रखा जाएगा।
  • एक (डिफ़ॉल्ट) ScheduledThreadPool, Executors वर्ग द्वारा बनाई गई के रूप में, एक न्यूनतम थ्रेड पूल है कि यह रहता है, तब भी जब निष्क्रिय है। यदि कोई नया कार्य आने पर व्यस्त होता है, तो यह के लिए एक नया धागा बनाता है, और इसे पूरा होने के 60 सेकंड बाद थ्रेड का निपटान करता है, जब तक इसकी आवश्यकता नहीं होती है।

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

public ThreadPoolExecutor(int corePoolSize, 
          int maximumPoolSize, 
          long keepAliveTime, 
          TimeUnit unit, 
          BlockingQueue<Runnable> workQueue) 

विभिन्न विकल्प आपको व्यवहार को सुदृढ़ करने की अनुमति देते हैं।

कुछ कार्य लंबे समय से कर रहे हैं ...

और मैं लंबे समय से मतलब है। आपके अधिकांश आवेदन जीवनकाल में (रीयलटाइम 2-वे कनेक्शन? सर्वर पोर्ट? मल्टीकास्ट श्रोता?)। उस स्थिति में, एक निष्पादक में अपना Runnable डालना हानिकारक है - मानक निष्पादक इससे निपटने के लिए डिज़ाइन किए गए हैं, और उनका प्रदर्शन खराब हो जाएगा।

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

अंगूठे का नियम

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

विस्तृत उत्तर के लिए धन्यवाद। मैंने 'अनुसूचित थ्रेडपूल 'की कोशिश की, लेकिन ऐसा लगता है कि यह नए धागे नहीं बनाते हैं जब यह सब थ्रेड व्यस्त होते हैं। मैंने इसे '(अनुसूचित थ्रेडपूलएक्सएटर) निष्पादकों के लिए 2 कोर धागे के साथ बनाया है। न्यूज शेड्यूलड थ्रेडपूल (2)' और फिर मैं बहुत सारे काम चलाता हूं, लेकिन 'getActiveCount() 'और' getLargestPoolSize() 'ऊपर कभी नहीं जाता 2. क्या मैं हो सकता हूं कुछ गलत कर रहा है? – Andranik

+1

@Andranik यह जांचने का एक अच्छा तरीका नहीं है कि थ्रेड गिनती बढ़ जाती है या नहीं। क्या आपने कई तंग-लूप कार्यों को सबमिट करने का प्रयास किया है? और आपको यह जांचना होगा कि एंड्रॉइड में यह वास्तव में एक असंबद्ध पूल आकार के साथ पूल बनाता है - मेरे पास केवल एसई जावा सेट एटीएम – Ordous

+0

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

5

आपके प्रश्न का उत्तर करने के लिए - हाँ, निर्वाहक का उपयोग कर नए धागे बनाने क्योंकि तुलना में बेहतर है:

  1. निर्वाहक अलग धागा पूल की एक चयन प्रदान करता है। यह पहले से मौजूद धागे के पुन: उपयोग की अनुमति देता है जो थ्रेड सृजन एक महंगी ऑपरेशन के रूप में प्रदर्शन को बढ़ाता है।
  2. यदि कोई थ्रेड मर जाता है, तो एक्जिक्यूटर एप्लिकेशन को प्रभावित किए बिना इसे नए थ्रेड के साथ बदल सकता है।
  3. बहु-थ्रेडिंग नीतियों में परिवर्तन बहुत आसान हैं, क्योंकि केवल निष्पादक कार्यान्वयन को बदलने की आवश्यकता है।
3

आदेश की टिप्पणी के आधार पर मैंने अपने कोड को केवल एक पूल के साथ काम करने के लिए संशोधित किया है।

public class App extends Application { 

    private ThreadPoolExecutor mPool; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     mPool = new ThreadPoolExecutor(5, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new SynchronousQueue<Runnable>()); 
    } 
} 


public void submitRunnableTask(Runnable task){ 
    if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){ 
     mPool.submit(task); 
    } else { 
     new Thread(task).start(); // Actually this should never happen, just in case... 
    } 
} 

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

+1

आप अपने प्रारंभिक प्रश्न से एक लंबा सफर तय कर चुके हैं। आप इसे संपूर्ण समाधान के रूप में पोस्ट करने से पहले बेहतर टिप्पणियों के लिए CodeReview.SE पर पोस्ट करना चाह सकते हैं। मैं यहां एक पेशकश करूंगा हालांकि: आप 1 पूल के साथ एक ही व्यवहार प्राप्त कर सकते हैं: 'mPool = new ThreadPoolExecutor (5, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, नया सिंक्रोनस्यूयू ()); '। – Ordous

+0

@ ओर्डस, धन्यवाद। मैंने अपना जवाब संपादित किया है। इसके अलावा मैंने आपके पहले उत्तर को सही के रूप में चिह्नित किया है, क्योंकि यह मेरे प्रारंभिक प्रश्न के बेहतर उत्तर देता है। – Andranik

संबंधित मुद्दे