2012-07-03 6 views
6

मैं जावा NIO का उपयोग कर एक सरल फ़ाइल सर्वर से एक का चयन धागा और कई कार्यकर्ता धागे के साथ (वास्तविक पढ़ने/लिखने के लिए) को लागू करने के साथ कर रहा हूँ जावा NIO SocketChannel.read()।multithread

कोड का मुख्य हिस्सा की तरह लग रहा है:

while (true) { 
    int num = selector.select(); 
    if (num > 0) { 
     Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); 
     final SelectionKey key = keys.next(); 
     keys.remove(); 

     if (key.isValid()) { 
      if (key.isAcceptable()) { 
       accept(key); 
      } else if (key.isReadable()) { 
       performReadInWorkerThread (key); 
      } else if (key.isWritable()) { 
       performWriteInWorkerThread (key); 
      } 
     } 
    } 
} 

आप कोड का टुकड़ा, जब एक पठनीय/लिखने योग्य चैनल चयन किया जाता है से देख सकते हैं, मैं पढ़ने ऑफलोड/चयन धागे से लिखना एक कार्यकर्ता थ्रेड के लिए।

अब समस्या यह है कि जब एक पठनीय चैनल कार्यकर्ता धागे को सौंप दिया जाता है, और इसे समाप्त होने से पहले/चैनल से पढ़ना शुरू होता है, तो चयन थ्रेड फिर से लूप करता है, और selector.select() पहले चयनित पठनीय चैनल का चयन करता है (क्योंकि अभी भी है चैनल कि है अभी तक पूरी तरह पहले से सौंपा कार्यकर्ता धागा से भस्म नहीं में इनपुट बफर), इसलिए फिर से चैनल एक और कार्यकर्ता धागा को सौंप दिया है, कई कार्यकर्ता धागे एक ही चैनल पढ़ने में जिसके परिणामस्वरूप।

मेरा मानना ​​है कि यह एक डिजाइन समस्या है। मेरा सवाल यह है कि मैं एक ही समय में एक चैनल पढ़ने के लिए केवल एक थ्रेड सुनिश्चित कर सकता हूं?

+0

मा जवाब आप एक सरल फ़ाइल सर्वर मैं NIO अवरुद्ध, या आईओ को अवरुद्ध का प्रयोग करेंगे चाहते हैं कि आप – Amith

+0

मदद मिल सकती है की पढ़ा हिस्से के लिए मा देखें। आईएमएचओ चयनकर्ताओं के साथ गड़बड़ करने से यह बहुत आसान है। –

उत्तर

6

क्यों? पढ़ा नहीं जाएगा। वर्तमान धागे में करो। आप इस तरह से अंतहीन समस्याओं के लिए हैं। आपको पढ़ने के थ्रेड पर पहुंचने से पहले OP_READ को अपनाना होगा, जो कि काफी आसान है, लेकिन कठिन हिस्सा यह है कि जब पढ़ा धागा पढ़ता है तो उसे OP_READ को फिर से पंजीकृत करना होगा, जिसके लिए या तो (i) चयनकर्ता की आवश्यकता होती है wakeup(), जो संभवतः कुछ भी करने के लिए चुनिंदा धागा को चलाने का कारण बनता है, जो अपर्याप्त है, या अन्यथा (ii) लंबित पुनर्गठन की कतार का उपयोग करें, जो अगली बार चयनकर्ता के बाद तक उस चैनल पर अगले पढ़ने में देरी करता है जागता है, जो भी अपर्याप्त है, या फिर आपको कतार में जोड़ने पर तुरंत चयनकर्ता को जागृत करना होगा, जो कुछ भी तैयार नहीं होने पर भी अपमानजनक है। मैंने कभी भी एक विश्वसनीय एनआईओ आर्किटेक्चर नहीं देखा है जो अलग-अलग चयन और धागे पढ़ता है।

ऐसा मत करो। यदि आपके पास मल्टीथ्रेडिंग होनी चाहिए, तो अपने चैनलों को समूहों में व्यवस्थित करें, प्रत्येक अपने स्वयं के चयनकर्ता और अपने स्वयं के धागे के साथ, और उन सभी धागे अपने स्वयं के पढ़ने को करें।

इसी तरह एक अलग थ्रेड में लिखने के लिए कोई जरूरत नहीं है। जब लिखने के लिए आपके पास कुछ लिखें तो बस लिखें।

+0

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

+0

नीवेक, मुझे लगता है कि ईजेपी ने केवल पढ़ने की प्रक्रिया का खुलासा किया, और उसका जवाब बहुत उचित लगता है। आप एक थ्रेड में पढ़ते हैं, लेकिन फिर आप अनुरोध डेटा को पार्स करने के लिए वर्कर थ्रेड पर स्विच करते हैं। बड़ी फ़ाइलों का रखरखाव करना - बेहतर nginx के लिए यदि इन फ़ाइलों, स्थिर रहे हैं बल्कि यह संभाल करने के लिए जावा बनाने से स्विच करने के लिए, फिर भी आप zerocopy सामान के लिए दे सकता है: http://www.ibm.com/developerworks/library/j-zerocopy/ – user486075

+0

@ नीवेक ईजेपी रिट है। जब आपका कनेक्शन स्वीकार होता है तो आपके प्रत्येक ग्राहक को अलग थ्रेड के रूप में कार्य करना होता है। – Amith

-1

चेक SelectionKey.cancel() विधि।

+0

मुझे 'रख-रखाव' कनेक्शन की आवश्यकता है, मैं कई अनुरोधों को पूरा करने के लिए खोले सॉकेट का उपयोग करूंगा, इसलिए मुझे चयन चयन रद्द नहीं करना चाहिए, मुझे अभी भी भविष्य में चैनल से पढ़ना होगा। – neevek

+0

यह वैसे भी समस्या को कहीं और ले जाएगा: मेरा जवाब देखें। – EJP

1

एनआईओ के लिए, केवल एक सिद्धांत को ध्यान में रखें: मुख्य चयन धागे में पढ़ें/लिखें। यह सिद्धांत हार्डवेयर प्रकृति का प्रतिबिंब है। चिंता न करें कि मुख्य चयन धागे में पढ़ना तेज़ नहीं है। आधुनिक सर्वर में, सीपीयू नेटवर्क कार्ड से हमेशा तेज होता है। तो नेटवर्क थ्रेड ऑपरेशंस की तुलना में एक थ्रेड में पढ़ना कोई भी अवरुद्ध नहीं है। पैकेट पढ़ने के लिए एक धागा पहले से ही पर्याप्त है। हमें किसी और धागे की आवश्यकता नहीं है।

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