[解決済み] Java HashMapのパフォーマンス最適化/代替案
質問
大きなHashMapを作りたいのですが、HashMapの中の
put()
のパフォーマンスが十分ではありません。何かアイデアはありますか?
他のデータ構造の提案も歓迎しますが、私はJava Mapのルックアップ機能が必要です。
map.get(key)
私の場合、2600万のエントリを持つマップを作成したいと思います。標準的なJava HashMapを使用すると、2~300万件の挿入の後、putレートが耐えられないほど遅くなります。
また、キーに異なるハッシュコード分布を使用することが役に立つかどうか、誰か知っていますか?
私のハッシュコード方式です。
byte[] a = new byte[2];
byte[] b = new byte[3];
...
public int hashCode() {
int hash = 503;
hash = hash * 5381 + (a[0] + a[1]);
hash = hash * 5381 + (b[0] + b[1] + b[2]);
return hash;
}
同じオブジェクトが同じハッシュコードを持つようにするために、加算の連想特性を使用しています。配列は0から51の値を持つバイトで、値はどちらの配列でも一度だけ使用されます。オブジェクトは、a 配列が同じ値 (どちらの順番でも) を含んでいれば等しく、b 配列も同様です。つまり、a = {0,1} b = {45,12,33} と a = {1,0} b = {33,45,12} は等しいということです。
EDIT、いくつかの注意点です。
-
2600万のエントリを格納するためにハッシュマップや他のデータ構造を使用することを批判する人が何人かいました。なぜこれが奇妙に思えるのか、私にはわかりません。 私には、古典的なデータ構造とアルゴリズムの問題のように見えます。2600 万の項目があり、それらをデータ構造にすばやく挿入し、データ構造から調べることができるようにしたいのですが、そのデータ構造とアルゴリズムを教えてください。
-
デフォルトのJava HashMapの初期容量を2600万に設定する が減少します。 性能を低下させます。
-
何人かの人は、データベースを使用することを提案し、いくつかの他の状況では、それは間違いなくスマートな選択肢です。しかし、私は本当にデータ構造とアルゴリズムの質問をしているのです。完全なデータベースはやりすぎで、優れたデータ構造ソリューションよりもはるかに遅いでしょう (結局のところ、データベースは単なるソフトウェアですが、通信とおそらくディスク オーバーヘッドがあります)。
どのように解決するのですか?
多くの人が指摘しているように
hashCode()
メソッドが原因でした。2600 万個の異なるオブジェクトに対して、約 20,000 個のコードしか生成していなかったのです。これは、ハッシュバケットあたり平均1,300個のオブジェクトということです。しかし、2 つの配列を 52 進数の数値に変換すると、すべてのオブジェクトに対して一意のハッシュ コードが得られることが保証されます。
public int hashCode() {
// assume that both a and b are sorted
return a[0] + powerOf52(a[1], 1) + powerOf52(b[0], 2) + powerOf52(b[1], 3) + powerOf52(b[2], 4);
}
public static int powerOf52(byte b, int power) {
int result = b;
for (int i = 0; i < power; i++) {
result *= 52;
}
return result;
}
配列をソートすることで、このメソッドが
hashCode()
契約を満たすように配列がソートされます。古い方法を使用すると、100,000 プットのブロックにわたる 1 秒あたりの平均プット数は、100,000 から 2,000,000 でした。
168350.17
109409.195
81344.91
64319.023
53780.79
45931.258
39680.29
34972.676
31354.514
28343.062
25562.371
23850.695
22299.22
20998.006
19797.799
18702.951
17702.434
16832.182
16084.52
15353.083
新しいメソッドを使用すると、次のようになります。
337837.84
337268.12
337078.66
336983.97
313873.2
317460.3
317748.5
320000.0
309704.06
310752.03
312944.5
265780.75
275540.5
264350.44
273522.97
270910.94
279008.7
276285.5
283455.16
289603.25
ずっとずっと良くなりました。 古い方法はすぐに停止してしまいましたが、新しい方法は良好なスループットを維持します。
関連
-
undefined[sonar] sonar:デフォルトのスキャンルール
-
配列定数は初期化子でのみ使用可能です。
-
swagger2 モデルが表示されない モデルが見つからない @ApiModel アノテーションが表示されない問題
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] JavaでNullPointerExceptionを回避する方法
-
[解決済み] JavaにおけるHashMapとHashtableの違いは何ですか?
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] HashMapを直接(リテラルに)初期化する方法は?
-
[解決済み】HashMap、LinkedHashMap、TreeMapの違いについて
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
java.sql.SQLException: executeQuery()でデータ操作文を発行できません。
-
Javaでよくある構文エラー
-
SLF4J: クラス・パスに複数のSLF4Jバインディングが含まれています。
-
StringBuilderが投げるArrayIndexOutOfBoundsExceptionの探索
-
Jsoup-Crawlingの動作
-
名前 'XXX' を持つ Bean の作成に失敗しました。自動依存関係の注入に失敗しました 解決方法
-
-bash: java: コマンドが見つからない 解決方法
-
JNIエンカウンターエラー:構造体またはユニオンではない何かでメンバー 'FindClass' のリクエスト
-
git pull appears現在のブランチに対するトラッキング情報がありません。
-
IDEAError:javaの依存性エラー。Annotation processing is not supported for module cycles...(アノテーション処理はモジュールサイクルではサポートされていません。