यहाँ एक और तकनीक है जिसे मैंने दूसरे दिन चलाया:
Collections.nCopies(8, 1)
.stream()
.forEach(i -> System.out.println(i));
Collections.nCopiesकॉल एक बनाता Listयुक्त nआप जो भी मान प्रदान की प्रतियां। इस मामले में यह बॉक्सिंग Integerमूल्य 1 है। बेशक यह वास्तव में nतत्वों के साथ एक सूची नहीं बनाता है ; यह एक "वर्चुअलाइज्ड" सूची बनाता है जिसमें केवल मान और लंबाई होती है, और getसीमा के भीतर कोई भी कॉल केवल मान लौटाता है। इस nCopiesविधि के आसपास किया गया है क्योंकि कलेक्शन फ्रेमवर्क को JDK 1.2 में वापस लाया गया था। बेशक, इसके परिणाम से एक स्ट्रीम बनाने की क्षमता जावा एसई 8 में जोड़ी गई थी।
बड़ी बात, एक ही तरह की लाइनों के बारे में एक ही काम करने का दूसरा तरीका।
हालांकि, यह तकनीक दृष्टिकोण IntStream.generateऔर IntStream.iterateदृष्टिकोण से तेज है , और आश्चर्यजनक रूप से, यह IntStream.rangeदृष्टिकोण से भी तेज है ।
के लिए iterateऔर generateपरिणाम शायद बहुत आश्चर्य की बात नहीं है। स्ट्रीम फ्रेमवर्क (वास्तव में, इन स्ट्रीम के लिए Spliterators) इस धारणा पर बनाया गया है कि लैम्ब्डा संभावित रूप से प्रत्येक बार अलग-अलग मान उत्पन्न करेगा, और यह कि वे एक अनबिके परिणाम उत्पन्न करेंगे। यह समानांतर विभाजन को विशेष रूप से कठिन बनाता है। iterateविधि क्योंकि प्रत्येक कॉल पिछले एक का परिणाम की आवश्यकता है भी इस मामले के लिए समस्याग्रस्त है। तो धाराओं का इस्तेमाल करके generateऔर iterateदोहराया स्थिरांक पैदा करने के लिए बहुत अच्छी तरह से नहीं करते हैं।
अपेक्षाकृत खराब प्रदर्शन rangeआश्चर्यजनक है। यह भी वर्चुअलाइज्ड है, इसलिए एलिमेंट्स वास्तव में सभी मेमोरी में मौजूद नहीं हैं, और साइज का पता ऊपर तक है। यह तेजी से और आसानी से समानांतर स्प्लिटर के लिए बनाना चाहिए। लेकिन यह आश्चर्यजनक रूप से बहुत अच्छा नहीं हुआ। शायद इसका कारण यह है कि rangeरेंज के प्रत्येक तत्व के लिए एक मूल्य की गणना करना है और फिर उस पर एक फ़ंक्शन को कॉल करना है। लेकिन यह फ़ंक्शन केवल इसके इनपुट को अनदेखा करता है और एक स्थिर रिटर्न देता है, इसलिए मुझे आश्चर्य है कि यह इनबिल्ड नहीं है और मार दिया गया है।
Collections.nCopiesतकनीक के बाद से वहाँ का कोई आदिम विशेषज्ञताओं हैं, आदेश मानों का प्रबंधन कैसे में unboxing / मुक्केबाजी करना है List। चूंकि मूल्य हर बार समान होता है, इसलिए यह मूल रूप से एक बार बॉक्सिंग किया जाता है और उस बॉक्स को सभी nप्रतियों द्वारा साझा किया जाता है । मुझे संदेह है कि बॉक्सिंग / अनबॉक्सिंग अत्यधिक अनुकूलित है, यहां तक कि आंतरिक भी है, और यह अच्छी तरह से इनलेट किया जा सकता है।
यहाँ कोड है:
public static final int LIMIT = 500_000_000;
public static final long VALUE = 3L;
public long range() {
return
LongStream.range(0, LIMIT)
.parallel()
.map(i -> VALUE)
.map(i -> i % 73 % 13)
.sum();
}
public long ncopies() {
return
Collections.nCopies(LIMIT, VALUE)
.parallelStream()
.mapToLong(i -> i)
.map(i -> i % 73 % 13)
.sum();
}
और यहाँ JMH परिणाम हैं: (2.8GHz Core2Duo)
Benchmark Mode Samples Mean Mean error Units
c.s.q.SO18532488.ncopies thrpt 5 7.547 2.904 ops/s
c.s.q.SO18532488.range thrpt 5 0.317 0.064 ops/s
Ncopies संस्करण में पर्याप्त मात्रा में विचरण होता है, लेकिन कुल मिलाकर यह रेंज संस्करण की तुलना में 20x तेज आराम से लगता है। (मैं यह मानने को तैयार हूँ कि मैंने कुछ गलत किया है, हालाँकि।)
मुझे आश्चर्य है कि nCopiesतकनीक कितनी अच्छी तरह काम करती है। आंतरिक रूप से यह बहुत विशेष नहीं करता है, वर्चुअलाइज्ड सूची की धारा के साथ बस उपयोग करके कार्यान्वित किया जा रहा है IntStream.range! मुझे उम्मीद थी कि इसे तेजी से आगे बढ़ाने के लिए एक विशेष स्प्लिटेटर बनाना आवश्यक होगा, लेकिन यह पहले से ही बहुत अच्छा लग रहा है।