Bazı test sonuçları
Bu soruya çok iyi cevaplar aldım - teşekkürler millet - bu yüzden bazı testler yapmaya ve hangi yöntemin gerçekten en hızlı olduğunu anlamaya karar verdim. Test ettiğim beş yöntem şunlardır:
- soruda sunduğum "ContainsKey" yöntemi
- Aleksandar Dimitrov tarafından önerilen "TestForNull" yöntemi
- Hank Gay tarafından önerilen "AtomicLong" yöntemi
- jrudolph tarafından önerilen "Trove" yöntemi
- phax.myopenid.com tarafından önerilen "MutableInt" yöntemi
Yöntem
İşte yaptığım şey ...
- aşağıda gösterilen farklar dışında özdeş olan beş sınıf yarattı. Her sınıf, sunduğum senaryo için tipik bir işlem yapmak zorundaydı: 10MB'lık bir dosyayı açmak ve okumak, daha sonra dosyadaki tüm kelime belirteçlerinin bir frekans sayımı yapmak. Bu sadece ortalama 3 saniye sürdüğünden, frekans sayımını (G / Ç değil) 10 kez yaptım.
- I / O operasyonunu değil 10 tekrarlama döngüsünü zamanladı ve esasen Ian Darwin'in Java Yemek Kitabı'ndaki yöntemini kullanarak toplam süreyi (saat cinsinden) kaydetti .
- beş testi de seri olarak gerçekleştirdi ve bunu üç kez daha yaptı.
- her yöntem için dört sonucun ortalaması alınmıştır.
Sonuçlar
İlgilenenler için önce sonuçları ve aşağıdaki kodu sunacağım.
ContainsKey O yöntemin hızına kıyasla her bir yöntemin hızını vereceğiz böylece yöntem, en yavaş beklendiği gibi.
- Anahtar : 30.654 saniye (taban çizgisi)
- AtomicLong: 29.780 saniye (1.03 kat daha hızlı)
- TestForNull: 28.804 saniye (1,06 kat daha hızlı)
- Trove: 26.313 saniye (1,16 kat daha hızlı)
- Değişken: 25.747 saniye (1.19 kat daha hızlı)
Sonuçlar
Sadece MutableInt yönteminin ve Trove yönteminin önemli ölçüde daha hızlı olduğu görülüyor, çünkü sadece% 10'dan fazla bir performans artışı sağlıyorlar. Bununla birlikte, iplik geçirme bir sorunsa, AtomicLong diğerlerinden daha çekici olabilir (gerçekten emin değilim). TestForNull'ı final
değişkenlerle de çalıştırdım , ancak fark önemsizdi.
Farklı senaryolarda bellek kullanımını profilli olmadığımı unutmayın. MutableInt ve Trove yöntemlerinin bellek kullanımını nasıl etkileyebileceğine dair iyi fikir sahibi olan herkesi duymaktan mutluluk duyarım.
Şahsen, MutableInt yöntemini en çekici buluyorum, çünkü herhangi bir üçüncü taraf sınıfı yüklemeyi gerektirmiyor. Dolayısıyla, onunla ilgili sorunlar keşfetmezsem, gitme ihtimalim budur.
Kod
İşte her yöntemin önemli kodu.
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();
define
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();
}