Javaの最適化、hashMapからの利益?
-
22-07-2019 - |
質問
このような多くの機能を備えた love Javaコードを(約150万回実行されるループで)提供しました。
code = getCode();
for (int intCount = 1; intCount < vA.size() + 1; intCount++)
{
oA = (A)vA.elementAt(intCount - 1);
if (oA.code.trim().equals(code))
currentName= oA.name;
}
次のように切り替えると、速度が大幅に向上しますか
code = getCode();
//AMap is a HashMap
strCurrentAAbbreviation = (String)AMap.get(code);
編集: vAのサイズは約50です。トリムは必要ではありません 必要はありませんが、50 *の代わりに50回呼び出すと間違いなく便利です* 150万。 vAのアイテムは一意です。
編集:いくつかのレスポンダーの提案で、私はそれをテストしました。結果は下部にあります。ありがとう。
解決
調べる方法は1つしかありません。
他のヒント
OK、OK、テストしました。
あなたの啓発の結果は次のとおりです。
ルーピング:18391ms ハッシュ:218ms
ルーピング:18735ms ハッシュ:234ms
ルーピング:18359ms ハッシュ:219ms
そのビットをリファクタリングすると思います。
フレームワーク:
public class OptimizationTest {
private static Random r = new Random();
public static void main(String[] args){
final long loopCount = 1000000;
final int listSize = 55;
long loopTime = TestByLoop(loopCount, listSize);
long hashTime = TestByHash(loopCount, listSize);
System.out.println("Looping: " + loopTime + "ms");
System.out.println("Hash: " + hashTime + "ms");
}
public static long TestByLoop(long loopCount, int listSize){
Vector vA = buildVector(listSize);
A oA;
StopWatch sw = new StopWatch();
sw.start();
for (long i = 0; i< loopCount; i++){
String strCurrentStateAbbreviation;
int j = r.nextInt(listSize);
for (int intCount = 1; intCount < vA.size() + 1; intCount++){
oA = (A)vA.elementAt(intCount - 1);
if (oA.code.trim().equals(String.valueOf(j)))
strCurrentStateAbbreviation = oA.value;
}
}
sw.stop();
return sw.getElapsedTime();
}
public static long TestByHash(long loopCount, int listSize){
HashMap hm = getMap(listSize);
StopWatch sw = new StopWatch();
sw.start();
String strCurrentStateAbbreviation;
for (long i = 0; i < loopCount; i++){
int j = r.nextInt(listSize);
strCurrentStateAbbreviation = (String)hm.get(j);
}
sw.stop();
return sw.getElapsedTime();
}
private static HashMap getMap(int listSize) {
HashMap hm = new HashMap();
for (int i = 0; i < listSize; i++){
String code = String.valueOf(i);
String value = getRandomString(2);
hm.put(code, value);
}
return hm;
}
public static Vector buildVector(long listSize)
{
Vector v = new Vector();
for (int i = 0; i < listSize; i++){
A a = new A();
a.code = String.valueOf(i);
a.value = getRandomString(2);
v.add(a);
}
return v;
}
public static String getRandomString(int length){
StringBuffer sb = new StringBuffer();
for (int i = 0; i< length; i++){
sb.append(getChar());
}
return sb.toString();
}
public static char getChar()
{
final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i = r.nextInt(alphabet.length());
return alphabet.charAt(i);
}
}
ええ、そうする可能性は十分にあります。適切なハッシュコードがある場合、HashMapからの取得は一定の時間になります。
しかし、あなたが本当に見つけることができる唯一の方法は、それを試すことです。
これは、マップの大きさと、hashCodeの実装の程度(コリジョンが発生しないなど)に依存します。
実際にプロファイリングをいくつか実行して、変更が必要かどうかを確認する必要があります。壊れていないものを修正するために時間を費やすことになります。
elementAt呼び出しよりも実際に私が際立っているのは、各反復で行っている文字列のトリミングです。私の腸は、それがより大きなボトルネックかもしれないと私に伝えますが、プロファイリングのみが実際に伝えることができます。
幸運
上記はvA.size()に対する線形検索のように見えるため、「はい」と言います。 vaはどれくらいですか?
YourKitのようなもの(または別のプロファイラーを挿入)を使用して、ループのこの部分がどれだけ高いかを確認してみませんか。
マップを使用することは、そのコードを後で維持するのに役立つ改善点です。
マップを使用できるかどうかは、(ベクトル?)に一意のコードが含まれているかどうかによって異なります。指定されたforループは、指定されたコードを持つリストの last オブジェクトを記憶します。これは、ハッシュが解決策ではないことを意味します。
小さな(安定した)リストサイズの場合、単純にリストをオブジェクトの配列に変換すると、読みやすさが向上するだけでなく、パフォーマンスが向上します。
上記のいずれにも当てはまらない場合は、少なくともイタレーターを使用してリストを検査し、読みやすさとパフォーマンスの向上(おそらく)を提供します。
依存。どれだけのメモリを獲得しましたか?
はるかに高速に推測できますが、プロファイルします。
ループはn回実行する必要があるため、ここでの主な要因はvAの大きさです。nはvAのサイズです。マップを使用すると、vAの大きさに関係なく、ループは発生しません。したがって、nが小さい場合、改善はわずかです。巨大な場合、改善は巨大になります。これは特に当てはまります。なぜなら、一致する要素を見つけた後でも、ループが続くからです!したがって、200万個の要素リストの要素1で一致するものが見つかった場合でも、最後の1,999,999個の要素を確認する必要があります!
はい、ほぼ確実に高速になります。 vAコンテンツが適切にハッシュ可能であると仮定すると、平均25回(50回の半分)のループは、ハッシュマップ検索よりも遅くなります。
ただし、vAコンテンツについて言えば、aMap.get(&quot; somekey&quot;)はキーを持つエントリを見つけられないため、aMapに挿入するときにトリムする必要があります。 &quot; somekey&quot;です。
実際には、ハッシュマップソリューションに切り替えなくても、vAに挿入するときにそれを行う必要があります。