2017-02-27 8 views
9

मैं जावा स्ट्रीम के साथ कुछ काम समानांतर करने का प्रयास करता हूं। चलो इस सरल उदाहरण पर विचार करें:जावा स्ट्रीम जेनरेटर अनॉर्डर्ड क्यों है?

Stream.generate(new Supplier<Integer>() { 
     @Override 
     public Integer get() { 
      return generateNewInteger(); 
     } 
    }) 
    .parallel() 
    .forEachOrdered(new Consumer<Integer>() { 
     @Override 
     public void accept(Integer integer) { 
      System.out.println(integer); 
     } 
    }); 

समस्या यह है कि यह forEachOrdered के लिए accept विधि कॉल नहीं है, यह केवल अगर मैं forEach का उपयोग काम करता है। मुझे लगता है कि है कि समस्या Stream.generate आंतरिक InfiniteSupplyingSpliterator कि ORDERED विशेषता नहीं है बनाता है।

सवाल क्यों है? ऐसा लगता है जैसे हम जानते हैं कि डेटा किस क्रम में उत्पन्न होता है। दूसरा सवाल यह है कि स्ट्रीम तत्वों की पीढ़ी के साथ समांतर धारा पर forEachOrdered कैसे करें?

+3

यह असाधारण है, क्योंकि विनिर्देश ऐसा कहता है। कारण यह पूरा नहीं होता है, यह है कि यह * अनंत * है, कार्यान्वयन विवरण के साथ संयुक्त। – Holger

+2

इसे लैम्ब्स के साथ कहीं अधिक लिखा जा सकता है। –

+0

असंबद्ध, लेकिन आप केवल '.forEachOrdered (System.out :: println) कर सकते हैं ' –

उत्तर

10

सबसे आसान जवाब है, Stream.generate असाधारण है, क्योंकि it’s specification ऐसा कहता है।

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

Stream.generate को अनदेखा के रूप में परिभाषित करने का इरादा Stream.iterate के साथ तुलना करते समय स्पष्ट हो सकता है, जो आदेश दिया गया है। iterate को पारित फ़ंक्शन को इसके पिछले तत्व प्राप्त होंगे, इसलिए तत्वों के बीच पिछले-बाद के संबंध हैं, इसलिए, एक ऑर्डरिंग। आपूर्तिकर्ता से पारित कर दिया Stream.generate पिछले एक तत्व प्राप्त नहीं होता है, दूसरे शब्दों में, जब केवल कार्यात्मक हस्ताक्षर पर विचार पिछले एक तत्व के लिए कोई संबंध नहीं है। यही कारण है कि Stream.generate(instance::statefulOp) के लिए Stream.generate(() -> constant) या Stream.generate(Type::new) उपयोग के मामलों की तरह, लेकिन कम के लिए काम करता है, जो इरादा प्राथमिक उपयोग के मामले होने के लिए नहीं लगता है। यह अभी भी काम करता है, अगर ऑपरेशन थ्रेड सुरक्षित है और आप स्ट्रीम की अनियमित प्रकृति के साथ रह सकते हैं।

आपका उदाहरण कभी प्रगति नहीं करता है कि forEachOrdered का कार्यान्वयन वास्तव में अनियंत्रित प्रकृति पर विचार नहीं करता है, लेकिन मुठभेड़ आदेश में विभाजित होने के बाद भाग को संसाधित करने का प्रयास करता है, यानी सभी उप-कार्य अपने तत्वों को बफर करने का प्रयास करते हैं, ताकि वे उप-कार्यों को अपने बाएं पूरा कर लेते हैं, ताकि वे उन्हें कार्रवाई में पास कर सकें। बेशक, बफरिंग और अनंत स्रोतों में अच्छी तरह से एक साथ खेलते हैं नहीं है, विशेष रूप से, के बाद से अंतर्निहित InfiniteSupplyingSpliterator उप-कार्य है कि अपने दम पर अनंत हैं में विभाजित कर देगा। सिद्धांत रूप में, एक बाएं कार्य है जो अपने तत्वों को सीधे कार्रवाई में खिला सकता है, लेकिन यह कार्य कतार में कहीं भी लगता है, सक्रिय होने की प्रतीक्षा कर रहा है, जो कभी नहीं होगा क्योंकि सभी कार्यकर्ता धागे पहले से ही अन्य अनंत उप प्रोसेसिंग में व्यस्त हैं -tasks। आखिरकार, पूरा ऑपरेशन OutOfMemoryError के साथ टूट जाएगा, यदि आप इसे काफी देर तक चलते हैं ...

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