私は再帰アルゴリズムによって計算された約200万の値をキャッシュするためにHashMapを使用します。私は、コレクションフレームワークのHashMap<Integer, Double>
、またはboolean useTrove
変数によって制御されるTroveライブラリのTIntDoubleHashMap
のいずれかを以下のコードのように使用します。(Trove THashMapと比較して)標準のJava HashMapを使用すると、HashMap以外のコードは遅く実行されます。
私はそれが実際にオートボクシングなどを回避して、put()
とget()
通話、約300msの約500msのHashMap<>
用に比べTHashMap
のために(合計で)実行するために取る、トローブライブラリがより速くなることを期待します。
を使用した場合の全体のプログラム実行時間は、HashMap<>
を使用した場合は6.7秒です。この違いは、put()
とget()
コールの実行時間の増加だけでは説明できません。
HashMap<>
と、この非常に増加したランタイムは、この実装はそれぞれint型/オブジェクトに箱詰めされる二重のニーズ として非効率的なかなりのメモリであり、これは メモリ使用量を増加すると、キャッシュを引き起こすという事実によって を駆動させ疑い
プログラムの他の部分ではミスしてしまいます。 この説明は意味がありますが、この 仮説をどのように確認/拒否できますか?
一般的に、このようなシナリオではアルゴリズムの最適化をどのように検討しますか?アルゴリズムのプロファイリングは、少なくともCPU時間だけが と考えられる場合は、
HashMap<>
が原因であることを容易に指摘しません。メモリ使用量の多いプログラムでは、メモリ使用量に優先順位を付ける必要があることを事前に知ることは問題なのでしょうか?
コードは以下のとおりです。
import java.util.HashMap;
import gnu.trove.map.hash.TIntDoubleHashMap;
class RuntimeStopWatch {
long elapsedTime;
long startTime;
RuntimeStopWatch() { reset(); }
void reset() { elapsedTime = 0; }
void start() { startTime = System.nanoTime(); }
void stop() {
long endTime = System.nanoTime();
elapsedTime += (endTime - startTime);
startTime = endTime;
}
void printElapsedTime(String prefix) {
System.out.format(prefix + "%dms\n", elapsedTime/1000000);
}
}
public class HashMapBehaviour {
static RuntimeStopWatch programTime = new RuntimeStopWatch();
static RuntimeStopWatch hashMapTime = new RuntimeStopWatch();
static HashMap<Integer, Double> javaHashMapCache;
static TIntDoubleHashMap troveHashMapCache;
static boolean useTrove;
public static void main(String[] args) {
// useTrove = true;
useTrove = false;
javaHashMapCache = new HashMap<>();
troveHashMapCache = new TIntDoubleHashMap();
programTime.start();
recursiveFunction(29, 29, 178956970);
programTime.stop();
programTime.printElapsedTime("Program: ");
hashMapTime.printElapsedTime("Hashmap: ");
}
static double recursiveFunction(int n, int k, int bitString) {
if (k == 0) return 0.0;
if (useTrove) {
hashMapTime.start();
if (troveHashMapCache.containsKey(bitString | (1 << n))) return troveHashMapCache.get(bitString | (1 << n));
hashMapTime.stop();
} else {
hashMapTime.start();
if (javaHashMapCache.containsKey(bitString | (1 << n))) return javaHashMapCache.get(bitString | (1 << n));
hashMapTime.stop();
}
double result = 0.0;
for (int i = 0; i < (n >> 1); i++) {
double play1 = recursiveFunction(n - 1, k - 1, stripSingleBit(bitString, i));
double play2 = recursiveFunction(n - 1, k - 1, stripSingleBit(bitString, n - i - 1));
result += Math.max(play1, play2);
}
if (useTrove) {
hashMapTime.start();
troveHashMapCache.put(bitString | (1 << n), result);
hashMapTime.stop();
} else {
hashMapTime.start();
javaHashMapCache.put(bitString | (1 << n), result);
hashMapTime.stop();
}
return result;
}
static int stripSingleBit(int bitString, int bitIndex) {
return ((bitString >> (bitIndex + 1)) << bitIndex) | (bitString & ((1 << bitIndex) - 1));
}
}