यहाँ एक और तकनीक है जिसे मैंने दूसरे दिन चलाया:
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
! मुझे उम्मीद थी कि इसे तेजी से आगे बढ़ाने के लिए एक विशेष स्प्लिटेटर बनाना आवश्यक होगा, लेकिन यह पहले से ही बहुत अच्छा लग रहा है।