一些测试结果
对于这个问题,我得到了很多很好的答案——谢谢大家——所以我决定运行一些测试,找出哪种方法实际上最快.我测试的五种方法如下:
- 我在the question年提出的"容器密钥"方法
- Aleksandar Dimitrov建议的"TestForNull"方法
- 汉克·盖伊提出的"原子长"方法
- 尤道夫提出的"藏宝法"
- phax建议的"可变点"方法.肌萎缩.通用域名格式
方法
我是这么做的...
- 创建了五个相同的类,除了下面显示的差异.每个类都必须执行我介绍的场景中的典型操作:打开一个10MB的文件并读取它,然后对文件中的所有单词标记执行频率计数.因为这平均只需要3秒钟,所以我让它执行了10次频率计数(而不是I/O).
- 对10次迭代的循环计时,但为not the I/O operation次,并使用Ian Darwin's method in the Java Cookbook记录了总花费的时间(以时钟秒为单位).
- 连续进行了所有五个测试,然后又做了三次.
- 平均每种方法的四个结果.
结果
我将首先向感兴趣的人展示结果和下面的代码.
正如预期的那样,容器密钥方法是最慢的,所以我将给出每种方法的速度与该方法的速度进行比较.
- 30.654秒(基线)
- 原子长: 29.780秒(速度的1.03倍)
- 28.804秒(快1.06倍)
- 26.313秒(是原来的1.16倍)
- 可变点: 25.747秒(速度的1.19倍)
结论
似乎只有可变点方法和珍宝方法的速度要快得多,因为只有它们的性能提升才超过10%.然而,如果线程是一个问题,原子长可能比其他的更具吸引力(我不确定).我还用final
个变量运行了TestForNull,但差异可以忽略不计.
请注意,我没有分析不同场景中的内存使用情况.我很高兴听到任何人对可变点和珍宝方法可能如何影响内存使用有很好的见解.
就我个人而言,我发现可变点方法最有吸引力,因为它不需要加载任何第三方类.所以,除非我发现它有问题,否则我最有可能走的是这条路.
密码
下面是每个方法的关键代码.
容器密钥
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);
}
原子长
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.原子长;
...
final ConcurrentMap<String, 原子长> map =
new ConcurrentHashMap<String, 原子长>();
...
map.putIfAbsent(word, new 原子长(0));
map.get(word).incrementAndGet();
珍宝
import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);
可变点
import java.util.HashMap;
import java.util.Map;
...
class 可变点 {
int value = 1; // note that we start at 1 since we're counting
public void increment () { ++value; }
public int get () { return value; }
}
...
Map<String, 可变点> freq = new HashMap<String, 可变点>();
...
可变点 count = freq.get(word);
if (count == null) {
freq.put(word, new 可变点());
}
else {
count.increment();
}