2017-06-29 138 views
2

我正在處理大量數據,這些數據正從硬盤讀取並放入HashMap。讀取過程已使用Externalized而不是Serializable進行了優化,因此實際數據量不是問題。實現HashMap插入的高吞吐量

這個過程中的瓶頸是HashMap<Long, Entity>,這個過程中填寫了這個瓶頸。我的代碼看起來如下:

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
    int nbEntries = in.readInt(); 
    entities = new HashMap<>(nbEntries); 
    for(int i = 0; i < nbEntries; i++) { 
     Entity entity = new Entity(0); 
     relation.readExternal(in); 
     //entities.put(entity.getId(), entity); //<-- Bottleneck! 
    } 
} 

正如比較:數據的讀出的4Gb需要秒包括插入HashMap和秒無插入。

是否有快速的方法將大量數據插入HashMap?數據不一定要保持HashMap。該地圖可能是不可變的,但訪問性能至關重要。

+0

如何劃分輸入數據並在ConcurrentHashMap上使用多線程? –

回答

1

閱讀和存儲數據與讀取數據和丟棄數據之間的比較是不公平的,因爲它不會給內存分配器帶來負擔。您可以快速地看到,運行下面的實驗是:

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
    int nbEntries = in.readInt(); 
    Entity[] entities = new Entity[nbEntries]; 
    for(int i = 0; i < nbEntries; i++) { 
     Entity entity = new Entity(0); 
     relation.readExternal(in); 
     entities[i] = entity; 
    } 
} 

現在,你把你的實體,而不是扔掉,定時獲取哈希映射更接近存儲實體的很多。由於將實體存儲在數組中幾乎是瞬時操作,所以在上述運行時間之前,您可以實現的改進不會太大。

+0

你是對的,就是這樣!我試圖填充一個數組,只要使用HashMap就花費了很多時間。這非常不幸。非常感謝你。 –

1

如果@dasblinkenlight是正確的(我認爲他是!)關於內存分配和垃圾回收是真正的瓶頸,那麼您可以通過使用更大的初始和最大堆大小來提高加載時間;例如使用-Xms-Xmx選項。但是,這也可能沒有多大幫助。

但是沒有更快的方法來做HashMap插入。你已經在做一件事(在你的代碼中),這會有所作爲。

+0

我剛剛注意到我在測試期間刪除了堆增量。增加它實際上減少了約80%的所需時間! –

+1

呃......這就是我所預言的。隨着更大的堆,你將減少GC的數量。由於GC正在複製* live *對象,並且您正在積聚越來越多的活動對象,因此減少GC的數量應該可以降低開銷。並且使初始堆大小具有相同的效果。 –

+0

太好了,非常感謝 –