いくつかのテスト結果
私はこの質問に対してたくさんの良い答えを得ました-おかげで-いくつかのテストを実行して、どの方法が実際に最も速いかを見つけることにしました。私がテストした5つの方法は次のとおりです。
- 私が紹介した「ContainsKey」メソッド 質問で
- Aleksandar Dimitrovによって提案された「TestForNull」メソッド
- Hank Gayによって提案された "AtomicLong"メソッド
- jrudolphが提案する "Trove"メソッド
- phax.myopenid.comによって提案された「MutableInt」メソッド
方法
これが私がしたことです...
- 以下に示す違いを除いて同一の5つのクラスを作成しました。各クラスは、私が提示したシナリオに典型的な操作を実行する必要がありました。10MBのファイルを開いて読み取り、次にファイル内のすべての単語トークンの頻度カウントを実行しました。これは平均3秒しかかからなかったので、頻度カウント(I / Oではなく)を10回実行してもらいました。
- I / O操作ではなく、 10回の反復のループの時間を計り、JavaクックブックのIan Darwinのメソッドを基本的に使用して、かかった合計時間(クロック秒)を記録しました。。
- 5つのテストすべてを連続して実行し、さらに3回テストしました。
- 各メソッドの4つの結果を平均しました。
結果
興味のある方のために、最初に結果と以下のコードを紹介します。
の 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は他のスレッドよりも魅力的である可能性があります(本当にわかりません)。TestForNullも実行しましたfinal
変数を使用が、違いはごくわずかでした。
さまざまなシナリオでのメモリ使用量をプロファイルしていないことに注意してください。MutableIntメソッドとTroveメソッドがメモリ使用量にどのように影響する可能性があるかについての洞察が得られた方からの連絡をお待ちしています。
個人的には、サードパーティのクラスをロードする必要がないため、MutableIntメソッドが最も魅力的だと思います。だから私がそれに問題を発見しない限り、それが私が行く可能性が最も高い方法です。
コード
以下は、各メソッドからの重要なコードです。
ContainsKey
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);
}
AtomicLong
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
...
final ConcurrentMap<String, AtomicLong> map =
new ConcurrentHashMap<String, AtomicLong>();
...
map.putIfAbsent(word, new AtomicLong(0));
map.get(word).incrementAndGet();
Trove
import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);
MutableInt
import java.util.HashMap;
import java.util.Map;
...
class MutableInt {
int value = 1; // note that we start at 1 since we're counting
public void increment () { ++value; }
public int get () { return value; }
}
...
Map<String, MutableInt> freq = new HashMap<String, MutableInt>();
...
MutableInt count = freq.get(word);
if (count == null) {
freq.put(word, new MutableInt());
}
else {
count.increment();
}