我希望这个问题对于这个论坛来说不是太基本,但我们会看到的。我想知道如何重构一些代码以获得更好的性能,这些代码已经运行了很多次了
假设我正在使用一个映射(可能是一个HashMap)创建一个单词频率列表,其中每个键都是一个字符串,其中包含正在计数的单词,值是一个整数,每次找到单词的标记时,该值都会递增
在Perl中,增加这样的值非常容易:
$map{$word}++;
但在Java中,它要复杂得多。以下是我目前的做法:
int count=map.containsKey(word)?map.get(word):0;
map.put(单词,计数+1);
这当然依赖于较新Java版本中的自动装箱功能。我想知道你能否提出一种更有效的方法来增加这样一个值。是否有很好的性能原因可以避免使用集合框架而使用其他框架
更新:我已经对几个答案进行了测试。见下文
一些测试结果
对于这个问题,我得到了很多很好的答案——谢谢各位——所以我决定运行一些测试,找出哪种方法实际上最快。我测试的五种方法如下:
- 我在问题
- Aleksandar Dimitrov建议的“TestForNull”方法
- Hank Gay提出的“原子长”方法
- jrudolph建议的“Trove”方法
- phax.myopenid.com建议的“MutableInt”方法
方法
这就是我所做的
- 创建了五个相同的类,除了下面显示的差异。每个类都必须执行我介绍的场景中的典型操作:打开一个10MB的文件并读入它,然后对文件中的所有单词标记执行频率计数。因为这平均只花了3秒钟,所以我让它执行了10次频率计数(不是I/O)
- 对10次迭代的循环进行计时,但不是I/O操作,并使用Java烹饪书中的Ian Darwin方法
- 在系列中执行所有五个测试,然后再执行三次
- 对每种方法的四个结果取平均值
结果
我将首先向感兴趣的人展示结果和下面的代码
正如所料,ContainsKey方法是最慢的,因此我将给出每个方法的速度,并与该方法的速度进行比较
- ContainsKey:30.654秒(基线)
- AtomicLong:29.780秒(速度的1.03倍)
- TestForNull:28.804秒(速度的1.06倍)
- Trove:26.313秒(速度的1.16倍)
- MutableInt:25.747秒(速度的1.19倍)
结论
似乎只有MutableInt方法和Trove方法的速度要快得多,因为只有它们的性能提升才超过10%。但是,如果线程是一个问题,那么AtomicLong可能比其他线程更有吸引力(我不太确定)。我还使用final变量运行了TestForNull,但差异可以忽略不计
请注意,我没有分析不同场景中的内存使用情况。我很高兴听到有人对MutableInt和Trove方法可能如何影响内存使用有很好的见解
我个人认为MutableInt方法最有吸引力,因为它不需要加载任何第三方类。所以除非我发现它有问题,否则我很可能会这样做
代码
下面是每个方法的关键代码
康纳斯基
导入java.util.HashMap;
导入java.util.Map;
…
地图<;字符串,整数>;freq=新HashMap<;字符串,整数>;();
…
int count=freq.containsKey(字)?freq.get(word):0;
频率输出(字,计数+1);
TestForNull
导入java.util.HashMap;
导入java.util.Map;
…
地图<;字符串,整数>;freq=新HashMap<;字符串,整数>;();
…
整数计数=freq.get(字);
如果(计数=null){
频率输出(字,1);
}
否则{
频率输出(字,计数+1);
}
原子长
导入java.util.concurrent.ConcurrentHashMap;
导入java.util.concurrent.ConcurrentMap;
导入java.util.concurrent.AtomicLong;
…
最终ConcurrentMap<;字符串,原子长度>;地图=
新ConcurrentHashMap<;字符串,原子长度>;();
…
图.putIfAbsent(单词,新原子长(0));
map.get(word.incrementAndGet();
宝藏
导入gnu.trove.tobjectnthashmap;
...
TObjectIntHashMap<;字符串>;freq=新的Tobjectnthashmap<;字符串>;();
...
频率调节器输出值(字,1,1);
可变点
导入java.util.HashMap;
导入java.util.Map;
…
类可变整型{
int value=1;//注意,我们从1开始计数
公共无效增量(){++value;}
public int get(){return value;}
}
…
地图<;字符串,可变整型>;freq=新HashMap<;字符串,可变整型>;();
…
MutableInt count=freq.get(word);
如果(计数=null){
freq.put(word,new MutableInt());
}
否则{
count.increment();
}