[英]Java hashmap vs hashset performance
我有一個由7.6M行組成的文件。 每行的形式為:A,B,C,D其中B,C,D是用於計算A的重要性級別的值,A是每個行唯一的字符串標識符。 我的方法:
private void read(String filename) throws Throwable {
BufferedReader br = new BufferedReader(new FileReader(filename));
Map<String, Double> mmap = new HashMap<>(10000000,0.8f);
String line;
long t0 = System.currentTimeMillis();
while ((line = br.readLine()) != null) {
split(line);
mmap.put(splitted[0], 0.0);
}
long t1 = System.currentTimeMillis();
br.close();
System.out.println("Completed in " + (t1 - t0)/1000.0 + " seconds");
}
private void split(String line) {
int idxComma, idxToken = 0, fromIndex = 0;
while ((idxComma = line.indexOf(delimiter, fromIndex)) != -1) {
splitted[idxToken++] = line.substring(fromIndex, idxComma);
fromIndex = idxComma + 1;
}
splitted[idxToken] = line.substring(fromIndex);
}
其中插入虛擬值0.0用於“分析”目的,splitted是為該類定義的簡單String數組。 我最初使用String的split()方法,但發現上面的更快。
當我運行上面的代碼時,解析文件需要12秒,這比我認為應該花費更多。 如果我,例如,用一個字符串向量替換HashMap並且只從每一行獲取第一個條目(即我沒有給它一個關聯的值,因為它應該是分攤的常量),整個文件可以讀取少於3秒。
這告訴我(i)HashMap中存在很多沖突(我試圖通過預先分配大小並相應地設置加載因子來最小化調整大小的數量)或者(ii)hashCode()函數以某種方式緩慢。 我懷疑它(ii)因為如果我使用HashSet,文件可以在4秒內讀取。
我的問題是:HashMap執行速度如此之慢的原因是什么? hashCode()對於這個大小的地圖是不夠的,還是從根本上忽略了一些東西?
HashMap與Vector:在HashMap中插入比在Vector中插入更昂貴。 雖然兩者都是攤銷的常量時間操作,但HashMap在內部執行許多其他操作(如生成hashCode,檢查碰撞,解決碰撞等),而Vector只是在末尾插入元素(增加結構的大小,如果需要)。
HashMap vs HashSet: HashSet內部使用HashMap。 因此,如果您將它們用於同一目的,則不應存在任何性能差異。 理想情況下,這兩者具有不同的目的,因此關於哪個更好的討論是無用的。
因為,你需要B,C,D作為A的值作為鍵,你一定要堅持使用HashMap。 如果你真的只想比較性能,可以將“null”而不是0.0作為所有鍵的值(因為這是HashSet在將鍵放入其支持的HashMap時使用的)。
更新:HashSet使用虛擬常量值(靜態final)插入HashMap,而不是null。 對於那個很抱歉。 你可以用任何常量替換你的0.0,性能應該類似於HashSet。
您可以使用更具內存效率的Collections庫。
我建議Eclipse Collections( https://www.eclipse.org/collections/ ),它有一個ObjectDoubleMap( https://www.eclipse.org/collections/javadoc/8.0.0/org/eclipse/collections/api /map/primitive/ObjectDoubleMap.html ),它是一個對象的映射(在你的例子中是String),它有一個double(yes,primitive double)作為關聯值。 它在處理內存和性能方面要好得多。
你可以通過這樣做獲得一個空的實例:
ObjectDoubleMaps.mutable.empty();
是的,檢查你的例子用0.0
作為虛擬值VS靜態最終常量作為虛擬值VS HashSet
。 這是粗略的比較,為了更好的精度,我建議使用JHM工具,但我的HashSet
性能與靜態常量幾乎相同,就像虛擬性能一樣。
因此,最有可能的是,低性能是由每行包裝0.0
虛擬值引起的Double.valueOf()
在編譯期間它被Double.valueOf()
替換,每次都顯式創建一個新的Double
對象)。
這可以解釋低性能,因為HashSet
預定義了靜態最終虛擬對象(不是null
,順便說一句)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.