2017-06-29 69 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

太好了,非常感谢 –