背景
我试图找到最快的(关于写速度)键值存储来支持我拥有的应用程序。商店的容量最多为15k键值对。我尝试过以下方法:
LinkedHashMap
,当地图中的商品数量达到15000时,重写removeEldestEntry以删除最旧的条目:
new LinkedHashMap<Long, Object>(10000, 0.75F, false) {
private static final long serialVersionUID = 1L;
protected boolean removeEldestEntry(Map.Entry<Long, Object> eldest) {
return size() > 15000;
}
};
LinkedList
,如果大小已经是max,则删除第一个元素(要获取带有键id
的元素,按顺序搜索列表):
new LinkedList<Object>() {
private static final long serialVersionUID = 1L;
public boolean add(Object o) {
while (size() >= 15000)
remove(0);
return super.add(o);
}
};
ModBuffer
,我能想到的最快(理论上)商店(在列表中,找到带有键id
的元素,按顺序搜索整个缓冲区):< / p>
public class ModBuffer<T> {
private T[] buffer = (T[]) new Object[15000];
public add(Long key, T value) {
int pos = (int) (key % (long) buffer.length);
buffer[pos] = value;
}
直观地说,似乎ModBuffer是最快写的。但事实证明LinkedList是最快的。我使用这些缓冲区来实现网络协议。使用LinkedList,我设法达到850Mbps。使用ModBuffer,它不会超过700Mbps。
问题:
为什么LinkedList的编写速度比简单的ModBuffer快得多?它是否以某种方式进行了优化,因为它是标准Java集合的一部分?我无法想到任何其他原因......这非常有趣。
答案 0 :(得分:0)
我怀疑模数运算符比添加到链表更慢。在ModBuffer
实现中,始终执行模数。另一方面,LinkedList
实现调用O(1)
size方法,然后调用另一个O(1)
add方法插入列表的开头。如果条目数不超过15k的最大值,则可以在while
条件下添加由于分支预测而导致的改进:
while (size() >= 15000)
remove(0);
如果您在循环中添加元素且条目数未达到最大值,则大部分时间都会返回false。
但是,对于大量条目,情况应该不是这样 - 模数缓冲区应该更有效。
答案 1 :(得分:0)
听起来你在谈论协议的速度,而不是你的缓存的写入速度。如果您的协议有重传部分,那么较低的速度可能是由ModBuffer的奇怪且可能较差的保留特性引起的。基于LinkedList的解决方案丢弃队列中最旧的记录,ModBuffer解决方案有效地丢弃随机记录;只要存在缓存冲突,它就会丢弃记录。也许重新传输那些丢失的记录的需要正在减慢你的速度。