2010-04-15 24 views
14

के साथ इस stackoverflow पर मेरी पहली पोस्ट है ... मुझे आशा है कि कोई मेरी मदद कर सकतेजावा प्रदर्शन समस्या LinkedBlockingQueue

मैं जावा 6 LinkedBlockingQueue के साथ एक बड़ा प्रदर्शन प्रतिगमन की है। पहले धागे में मैं कुछ ऑब्जेक्ट उत्पन्न करता हूं जो मैं कतार में धक्का देता हूं, दूसरे थ्रेड में मैं इन ऑब्जेक्ट को खींचता हूं। प्रदर्शन प्रतिगमन तब होता है जब LinkedBlockingQueue की विधि को अक्सर बुलाया जाता है। मैंने पूरे कार्यक्रम की निगरानी की और take() विधि ने समग्र रूप से सबसे अधिक समय दावा किया। और प्रवाह से ~ 58MB/s 0.9 MB/s जाता है ...

कतार पॉप और ले तरीकों इस वर्ग

public class C_myMessageQueue { 

    private static final LinkedBlockingQueue<C_myMessageObject> x_queue = new LinkedBlockingQueue<C_myMessageObject>(50000); 

    /** 
    * @param message 
    * @throws InterruptedException 
    * @throws NullPointerException 
    */ 
    public static void addMyMessage(C_myMessageObject message) 
      throws InterruptedException, NullPointerException { 
     x_queue.put(message); 
    } 

    /** 
    * @return Die erste message der MesseageQueue 
    * @throws InterruptedException 
    */ 
    public static C_myMessageObject getMyMessage() throws InterruptedException { 
     return x_queue.take(); 
    } 
} 

कैसे कर सकते हैं मैं धुन take() से एक स्थिर विधि के साथ कहा जाता है गिरफ्तारी कम से कम 25 एमबी/एस पूरा करने के लिए विधि, या क्या कोई अन्य वर्ग है जिसका उपयोग मैं कर सकता हूं जो "कतार" पूर्ण या खाली होने पर अवरुद्ध होगा।

तरह का संबंध

बार्ट

पी.एस .: मेरा बुरा अंग्रेजी के लिए खेद, मैं जर्मनी से हूँ;)

+1

एमबी/एस व्यर्थ है। ले लो() एक संदर्भ मिलता है। चाहे उसका पेलोड (संदर्भ के शब्द के अलावा) कुछ बाइट्स या कई मेगाबाइट्स है, कतार के लिए अप्रासंगिक है। –

+0

मुझे पता है ... लेकिन मैंने प्रतिगमन की विस्तारशीलता को मजबूर करने की कोशिश की;) – lofthouses

+0

क्या आप पहले कतार में 5000 तत्व जोड़ने की कोशिश कर सकते हैं, फिर ले लेते हैं यह देखने के लिए कि प्रत्येक कितना समय व्यतीत करता है? –

उत्तर

16

आपका निर्माता धागा बस उपभोक्ता उपभोग से अधिक तत्व रखता है, इसलिए कतार अंततः इसकी क्षमता सीमा को हिट करती है, इस प्रकार निर्माता प्रतीक्षा करता है।

मेरी मूल जवाब समेकन के बाद से अब हम मूल रूप से पूरी तस्वीर है:

  • आप (हर पंक्ति एक है) बहुत तेज put() है, जहां भी नित्य take()s करके LinkedBlockingQueue के निहित प्रवाह सीमा मारा, शून्य आगे प्रसंस्करण के साथ, जारी नहीं रख सकते हैं। (वैसे यह दिखाता है कि इस संरचना में, आपके जेवीएम और मशीन पर वैसे भी,() एस पढ़ते हैं कम से कम थोड़ा अधिक महंगा है)।
  • चूंकि उपभोक्ताओं को लॉक करने के लिए एक विशेष लॉक है, इसलिए अधिक उपभोक्ता धागे डालने से संभवतः मदद नहीं मिल सकती है (यदि आपका उपभोक्ता वास्तव में कुछ प्रसंस्करण कर रहा था और जो थ्रूपुट को बांध रहा था, तो अधिक उपभोक्ताओं को जोड़ने में मदद मिलेगी। इसके लिए बेहतर कतार कार्यान्वयन हैं एक से अधिक उपभोक्ताओं (या निर्माता) के साथ एक परिदृश्य, आप SynchronousQueue, ConcurrentLinkedQueue और jsr166y के आने वाले TransferQueue को आजमा सकते हैं)।

कुछ सुझाव:

  • प्रयास करें (अधिक मोटे सुक्ष्म वस्तुओं बनाने के लिए, आपके मामले में, ताकि प्रत्येक कतार की भूमि के ऊपर वास्तविक काम है कि उत्पादन धागा से उतारा है साथ संतुलित है, यह ऐसा लगता है कि आप उन वस्तुओं के लिए अधिक संचार ओवरहेड बनाते हैं जो काम की नगण्य मात्रा का प्रतिनिधित्व करते हैं)
  • आप निर्माता को उपभोक्ता को कुछ उपभोग करने वाले काम को ऑफ़लोड करके भी मदद कर सकते हैं (जब काम करने के लिए मूर्खतापूर्ण प्रतीक्षा में बहुत अधिक बिंदु नहीं है)।

/के बाद जॉन डब्ल्यू ठीक ही बाहर अपने मूल जवाब

+0

मैं विश्वास नहीं करता कि एक StringBuilder.append ("-----"); उपभोक्ता थ्रेड में उत्पादक धागे – lofthouses

+0

में बहुत अंकगणितीय परिचालनों की तुलना में बहुत धीमी है, समस्या होने पर कतार के आकार को स्पष्ट करें। यही एकमात्र तरीका है जिसे हम सुनिश्चित कर सकते हैं कि यह निर्माता या उपभोक्ता धीमा है या नहीं। स्ट्रिंग ऑपरेशंस भी धीमा हो सकता है, इस तरह की धारणाओं पर निर्भर न हों, केवल जब आप समस्या देखते हैं, तो जांच करें कि कतार लगभग खाली है या लगभग पूर्ण है। –

+0

(मुझे संदेह है कि आप अनावश्यक रूप से बहुत अच्छी तरह से तैयार वस्तुओं को बनाते हैं। यदि आवश्यक हो तो आप कतार ओवरहेड को कम करने के लिए बड़े पैक में से कुछ को बंडल करने का भी प्रयास कर सकते हैं)। –

1

यह कहना क्या भरने की प्रक्रिया के बारे में कुछ जानने के बिना होता है मुश्किल है।

यदि addMyMessage कम बार कहा जाता है - शायद आपके आवेदन के एक अलग हिस्से में प्रदर्शन समस्या के कारण - take विधि को प्रतीक्षा करनी है।

इस तरह यह लगता है कि take अपराधी है, लेकिन वास्तव में यह आपके आवेदन का भरने वाला हिस्सा है।

+0

भरने वाला थ्रेड अपराधी नहीं है, थ्रूपुट थ्रेड होने पर उपभोक्ता थ्रेड पर भरने वाला धागा प्रतीक्षा करता है (विजुअलवम प्रोफाइलर के साथ देखा जाता है)। जब भरने वाले थ्रेड को उपभोक्ता पर इंतजार नहीं करना पड़ा था तो थ्रूपुट वास्तव में अच्छा था, कम से कम 58 एमबी/एस। विधि ले पर उपभोक्ता धागा प्रतीक्षा करता है, कम से कम ar उपभोक्ता कार्य में आपरेशन ... मैं भी ArrayBlockingQueue ... एक ही खेल, धीमी गति से विधि ले लिए उपभोक्ता प्रतीक्षा, और भराव इंतजार क्योंकि कतार की कोशिश की पूर्ण ps: प्रोग्राम एक प्रति कार्य है पीपीएस: आपके उत्तर के लिए धन्यवाद;) – lofthouses

0

यह संभव हो सकता है कि आपका एप्लिकेशन जावा 6, विशेष रूप से "पक्षपातपूर्ण लॉकिंग" सुविधा में लॉकिंग से संबंधित परिवर्तनों से प्रभावित हो।

-XX:-UseBiasedLocking स्विच का उपयोग करके इसे अक्षम करने का प्रयास करें और देखें कि इससे कोई फर्क पड़ता है या नहीं।

अधिक जानकारी के लिए देखें: http://java.sun.com/performance/reference/whitepapers/6_performance.html

+0

सुराग के लिए धन्यवाद, लेकिन यह कुछ भी नहीं बदला ... उपभोक्ता धागे में लेना() 96.7% समय लेता है। मेरी राय में लेआउट विधि धीमा है ... – lofthouses

+0

शायद यह उस विधि के कार्यान्वयन को देखने में मदद करता है। मुझे वहां कुछ अजीब नहीं मिला। –

+0

मैं करने के लिए कुछ भी नहीं मिला है, लेकिन तथ्य यह है कि ले इस सूत्र – lofthouses

1

आकार और कचरा संग्रहण कतार की वजह से प्रदर्शन की समस्याओं के बारे में मिले this interesting post

+0

हम्म, एक interssting लेख में ज्यादातर समय ले लिया है, लेकिन यह तो मेरी समस्या ... – lofthouses

0

निश्चित रूप से कुछ भी नहीं बता सकता है। लेकिन आप BlockingQueue कार्यान्वयन को बदलने की कोशिश कर सकते हैं (बस एक प्रयोग के रूप में)।

आपने आरंभिक क्षमता 50k सेट की है और LinkedBlockingQueue का उपयोग करें। उसी क्षमता के साथ ArrayBlockingQueue आज़माएं, आप fair पैरामीटर के साथ भी खेल सकते हैं।

+0

कि मेरा आखिरी कोशिश हो जाएगा के लिए कुछ भी नहीं बदला है ... और मैं javolution या ऐसा कुछ के साथ खेलेंगे ... या यह एक बुरा विचार है? – lofthouses

+0

मुझे लगता है कि वह एक एकल निर्माता, एकल उपभोक्ता परिदृश्य का मतलब है, इसलिए निष्पक्षता अप्रासंगिक होनी चाहिए। जिज्ञासा है कि LinkedBlockingQueue हालांकि एक उचित पैरामीटर का पर्दाफाश नहीं करता है। –

3

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

ArrayBlockingQueue आज़माएं और प्रदर्शन को मापें।

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

+0

आप कठोर हैं, लेकिन arrayBQ और linkedBQ के बीच केवल न्यूनतम प्रदर्शन अंतर है। और रिग्रेशन अभी भी – lofthouses

3

यहाँ चीजों की एक जोड़ी की कोशिश कर रहे हैं:

एक ArrayBlockingQueue साथ LinkedBlockingQueue बदलें। इसमें कोई हानिकारक संदर्भ नहीं है और कतार भरने पर बेहतर व्यवहार किया जाता है। विशेष रूप से, LinkedBlockingQueue के 1.6 कार्यान्वयन के बाद, तत्वों का पूर्ण जीसी तब तक नहीं होगा जब तक कि कतार वास्तव में खाली न हो जाए।

यदि निर्माता पक्ष लगातार उपभोक्ता पक्ष निष्पादित कर रहा है, तो "थोक" लेने के लिए drain या drainTo का उपयोग करने पर विचार करें।

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

+0

डर का विरोध करता है, मैंने इसे स्वयं क्यों नहीं किया ... इसलिए मैं इसे आजमाउंगा :) – lofthouses

+0

मुझे संदेह है कि नाली() मदद करेगा। उपभोक्ता की समस्या उपभोक्ता के लॉक के लिए विवाद नहीं है (यह केवल एक उपभोक्ता धागा है, उपभोक्ता लॉक लेना अनचाहे और/तेज/है)। मौलिक मुद्दा यह है कि उपभोक्ता धीमा है, इसके माध्यम से कम डेटा प्रवाह होता है, इसलिए निर्माता, कोई फर्क नहीं पड़ता कि (बिना बहने वाली कतार के), उस कम प्रवाह से बाध्य होने जा रहा है - मेरा जवाब भी देखें। –

+0

ArrayBlockingQueue LinkedBlockingQueue की तुलना में धीमी हो जाएगा के रूप में यह डाल के लिए()) एकल ताला उपयोग करता है और() ले() जबकि LinkedBlockingQueue पुट के लिए 2 ताले उपयोग करता है और ले (और उत्पादक और उपभोक्ता सिंक्रनाइज़ करता है केवल जब कतार खाली/भरा हुआ है। –

0

को गुमराह किया गया था डाल करने और अपने blockingqueues से वस्तु लेने के लिए कच्चे प्रदर्शन भूमि के ऊपर अपने टोंटी (और नहीं slow-producer/consumer problem) है ओर इशारा अद्यतन, आप प्राप्त कर सकते हैं वस्तुओं के बैचिंग के साथ बड़े प्रदर्शन में सुधार: उदाहरण के लिए, दंडित वस्तुओं को डालने या लेने के बजाय, आप ऑब्जेक्ट्स की मोटे अनाज वाली सूचियां डालते हैं या लेते हैं।यहां एक कोड स्निपेट है:

ArrayBlockingQueue<List<Object>> Q = new ArrayBlockingQueue<List<Object>>(); 

// producer side 
List<Object> l = new ArrayList<Object>(); 
for (int i=0; i<100; i++) { 
    l.add(i); // your initialization here 
} 
Q.put(l); 

// consumer side 
List<Object> l2 = Q.take(); 
// do something 

बैचिंग परिमाण के क्रम से आपके प्रदर्शन को बढ़ावा दे सकती है।

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