कुछ परीक्षण के परिणाम
मैंने इस सवाल का बहुत अच्छा जवाब दिया है - धन्यवाद दोस्तों - इसलिए मैंने कुछ परीक्षण चलाने का फैसला किया और पता लगाया कि वास्तव में कौन सी विधि सबसे तेज़ है। मैंने जिन पांच तरीकों का परीक्षण किया वे ये हैं:
- प्रश्न में प्रस्तुत "ContainsKey" विधि
- अलेक्जेंडर दिमित्रोव द्वारा सुझाए गए "टेस्टफ़ोरनुल" विधि
- हांक गे द्वारा सुझाई गई "एटॉमिकलॉन्ग" विधि
- "ट्रोव" विधि जोर्डोफ द्वारा सुझाई गई है
- phax.myopenid.com द्वारा सुझाई गई "MutableInt" विधि
तरीका
यहाँ मैंने क्या किया है ...
- नीचे दिखाए गए मतभेदों को छोड़कर पांच कक्षाएं बनाई गईं जो समान थीं। प्रत्येक वर्ग को मेरे द्वारा प्रस्तुत परिदृश्य का एक ऑपरेशन विशिष्ट प्रदर्शन करना था: एक 10 एमबी फ़ाइल खोलना और इसे पढ़ना, फिर फ़ाइल में सभी शब्द टोकन की एक आवृत्ति गणना करना। चूंकि इसने केवल 3 सेकंड का औसत लिया, इसलिए मैंने 10 बार आवृत्ति गणना (I / O नहीं) की थी।
- 10 पुनरावृत्तियों के लूप को समयबद्ध किया, लेकिन I / O ऑपरेशन को नहीं किया और जावा कुकबुक में इयान डार्विन की विधि का उपयोग करके अनिवार्य रूप से लिया गया कुल समय (घड़ी सेकंड में) दर्ज किया ।
- श्रृंखला में सभी पांच परीक्षण किए, और फिर तीन बार ऐसा किया।
- प्रत्येक विधि के लिए चार परिणामों को औसत किया।
परिणाम
मैं पहले परिणाम और नीचे दिए गए कोड को उन लोगों के लिए प्रस्तुत करूँगा जो रुचि रखते हैं।
ContainsKey विधि, उम्मीद थी के रूप में, सबसे धीमी है, इसलिए मुझे लगता है कि विधि की गति की तुलना में प्रत्येक विधि की गति दे देंगे।
- ContainsKey: 30.654 सेकंड (आधार रेखा)
- एटॉमिकलॉन्ग: 29.780 सेकंड (तेजी से 1.03 गुना)
- TestForNull: 28.804 सेकंड (उपवास के रूप में 1.06 बार)
- ट्रोव: 26.313 सेकंड (तेजी से 1.16 बार)
- MutableInt: 25.747 सेकंड (1.19 गुना तेज)
निष्कर्ष
ऐसा प्रतीत होता है कि केवल MutableInt पद्धति और Trove विधि काफी तेज हैं, केवल इसमें वे 10% से अधिक का प्रदर्शन बढ़ा देते हैं। हालांकि, अगर थ्रेडिंग एक मुद्दा है, तो एटॉमिकलॉन्ग दूसरों की तुलना में अधिक आकर्षक हो सकता है (मुझे वास्तव में यकीन नहीं है)। मैंने TestForNull के साथ भी दौड़ लगाईfinal
चर के , लेकिन अंतर नगण्य था।
ध्यान दें कि मैंने अलग-अलग परिदृश्यों में मेमोरी के उपयोग को कम नहीं किया है। मुझे किसी को भी यह सुनकर खुशी होगी कि किस प्रकार म्यूचुअलेबल और ट्रोव के तरीकों में अच्छी अंतर्दृष्टि है, जो स्मृति उपयोग को प्रभावित करने की संभावना है।
व्यक्तिगत रूप से, मुझे MutableInt विधि सबसे आकर्षक लगती है, क्योंकि इसमें किसी भी तृतीय-पक्ष की कक्षाओं को लोड करने की आवश्यकता नहीं होती है। इसलिए जब तक मैं इसके साथ समस्याओं का पता नहीं लगाता, यही वह रास्ता है जब मैं सबसे अधिक संभावना रखता हूं।
कोड
यहाँ प्रत्येक विधि से महत्वपूर्ण कोड है।
ContainsKey
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
TestForNull
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
Integer count = freq.get(word);
if (count == null) {
freq.put(word, 1);
}
else {
freq.put(word, count + 1);
}
AtomicLong
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
...
final ConcurrentMap<String, AtomicLong> map =
new ConcurrentHashMap<String, AtomicLong>();
...
map.putIfAbsent(word, new AtomicLong(0));
map.get(word).incrementAndGet();
निधि
import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);
MutableInt
import java.util.HashMap;
import java.util.Map;
...
class MutableInt {
int value = 1; // note that we start at 1 since we're counting
public void increment () { ++value; }
public int get () { return value; }
}
...
Map<String, MutableInt> freq = new HashMap<String, MutableInt>();
...
MutableInt count = freq.get(word);
if (count == null) {
freq.put(word, new MutableInt());
}
else {
count.increment();
}