最も効率的なJavaコレクションライブラリは何ですか?
数年前、私は多くのJavaを実行し、当時は trove が最高(最も効率的)Javaであるという印象を持ちました。 _コレクションの実装。しかし、「 最も便利な無料Javaライブラリ? 」という質問への回答を読んだとき、 trove ほとんど言及されていません。では、どのJavaコレクションライブラリが最適ですか?
UPDATE:明確にするために、何百万ものエントリをハッシュテーブルなどに保存する必要があるときに使用するライブラリを主に知りたいランタイムとメモリフットプリント)。
検査から、Troveはプリミティブ型のコレクションのライブラリにすぎないように見えます。JDKの通常のコレクションに多くの機能を追加することを意図しているわけではありません。
個人的に(そして私は偏見がある)私は大好き Guava (以前のGoogle Java Collectionsプロジェクトを含む)。それは、さまざまなタスク(コレクションを含む)を、コレクション操作が私のコードでボトルネックを形成することはめったにないので(私の経験では)、これはより効率的かもしれないがコードを読みやすくしないコレクションAPIよりも「良い」です。
TroveとGuavaのオーバーラップがほとんどないことを考えると、おそらくコレクションライブラリから実際に探しているものを明確にすることができます。
問題は、(現在)大量のデータを格納することです。これらのデータは、マップにint
などのプリミティブ型を使用して表すことができます。ここでの回答のいくつかは、私の意見では非常に誤解を招くものです。理由を見てみましょう。
trove からベンチマークを変更して、ランタイムとメモリ消費の両方を測定しました。また、このベンチマークに [〜#〜] pcj [〜#〜] を追加しました。これは、プリミティブ型の別のコレクションライブラリです(これを広範囲に使用しています)。 「公式の」Troveベンチマークは、IntIntMapsをJavaコレクションのMap<Integer, Integer>
と比較しません。おそらくIntegers
を格納することとints
を格納することは技術的な観点からは異なります。ユーザーはこの技術的な詳細を気にしないかもしれませんが、ints
で表現可能なデータを効率的に保存したいと考えています。
まず、コードの関連部分:
new Operation() {
private long usedMem() {
System.gc();
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
// trove
public void ours() {
long mem = usedMem();
TIntIntHashMap ours = new TIntIntHashMap(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
ours.put(i, i);
}
mem = usedMem() - mem;
System.err.println("trove " + mem + " bytes");
ours.clear();
}
public void pcj() {
long mem = usedMem();
IntKeyIntMap map = new IntKeyIntOpenHashMap(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
map.put(i, i);
}
mem = usedMem() - mem;
System.err.println("pcj " + mem + " bytes");
map.clear();
}
// Java collections
public void theirs() {
long mem = usedMem();
Map<Integer, Integer> map = new HashMap<Integer, Integer>(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
map.put(i, i);
}
mem = usedMem() - mem;
System.err.println("Java " + mem + " bytes");
map.clear();
}
データはプリミティブints
として来ると思いますが、これは正気のようです。しかし、これはJava utilの実行時ペナルティを意味します。これは、プリミティブなコレクションフレームワークには必要ない自動ボクシングのためです。
WinXP、jdk1.6.0_10でのランタイムの結果(もちろんgc()
呼び出しなし):
100000 put操作100000には操作が含まれます Javaコレクション1938 ms 203 ms trove 234 ms 125 ms pcj 516 ms 94 ms
これはすでに抜本的に思えるかもしれませんが、これがそのようなフレームワークを使用する理由ではありません。
その理由は、メモリのパフォーマンスです。 100000 int
エントリを含むマップの結果:
Javaコレクションは6644536〜7168840バイトの間で振動します trove 1853296バイト pcj 1866112バイト
Javaコレクションは、プリミティブコレクションフレームワークと比較して4倍以上のメモリを必要とします。つまりディスクIOにより実行時のパフォーマンスが大幅に低下します。これは重要です。これは重要です。理由は、 高スケーラビリティ を参照してください。
私の経験では、高いメモリ消費はJavaの最大のパフォーマンスの問題であり、当然、ランタイムパフォーマンスも低下します。プリミティブコレクションフレームワークはここで本当に役立ちます。
だから:いいえ、Java.utilは答えではありません。そして、「機能を追加する」Javaコレクションは、効率について尋ねるポイントではありません。また、最新のJDKコレクションは、not特別なTroveコレクション」。
免責事項:ここでのベンチマークは完全とはほど遠いものであり、完璧でもありません。私が多くのプロジェクトで経験したポイントを家に戻すことを意図しています。プリミティブコレクションは、魚のようなAPIを許容するのに十分役立ちます-if大量のデータを扱う場合。
私はこれが古い投稿であり、ここにたくさんの答えがあることを知っています。しかし、上記の答えは表面的であり、ライブラリを提案するという点では単純化されています。ここに示されているさまざまなベンチマークでうまく機能するライブラリはありません。私が導き出す唯一の結論は、パフォーマンスとメモリ、特にプリミティブ型を扱うことに関心がある場合、jdk以外の選択肢を見るだけの価値があるということです。
ベンチマークの仕組みとカバーされているライブラリの観点から、より適切な分析を次に示します。 これ は、mahout devリストのスレッドです。
カバーされるライブラリは
2015年6月更新:残念ながら、元のベンチマークはもう利用できず、少し古くなっています。 ここ は、他の誰かによって行われたかなり最近(2015年1月)のベンチマークです。元のリンクほど包括的ではなく、インタラクティブな探索ツールもありません。
他のコメンテーターが気づいているように、「効率的」の定義は広いネットをキャストします。しかし、まだ誰も Javolutionライブラリ について言及していません。
ハイライトのいくつか:
Javolutionディストリビューションにはベンチマークスイートが含まれているため、他のライブラリ/ビルトインコレクションと比較することができます。
考慮すべきいくつかのコレクションライブラリ:
私は何よりもまず、JDKコレクションライブラリに手を伸ばします。それはあなたがする必要がある最も一般的な事柄をカバーし、明らかにあなたにはすでに利用可能です。
Googleコレクションは、おそらくJDK以外では最高の高品質ライブラリです。頻繁に使用され、十分にサポートされています。
Apache Commons Collectionsは古く、「料理人が多すぎる」という問題に少し悩まされていますが、役に立つものもたくさんあります。
Troveには、プリミティブキー/値などのケース向けの非常に特殊なコレクションがあります。最近では、最新のJDKで、Java 5+コレクションと同時使用ケースを使用すると、JDKコレクションは専用のTroveコレクションよりも優れていることがわかります。
同時実行のユースケースが本当に高い場合は、ロックフリーの実装であり、適切なユースケースがある場合はConcurrentHashMapを踏むことができる、大規模なlibのNonBlockingHashMapのようなものを必ずチェックアウトする必要があります。
何百万ものString
をマップに保存するには、 http://code.google.com/p/flatmap をご覧ください。
Java.util
明らかな答えで申し訳ありませんが、ほとんどの用途では、デフォルトの Java Collections で十分です。
私は source-forgeのhappy-collections からのhappy-collectionsの開発者です
Troveにはいくつかの利点があります。
とはいえ、Troveが書かれてからjdkコレクションを改善するために多くのことが行われてきました。
しかし、それが私にとって魅力的なのはハッシュ戦略です... Googleがその概要を読んで読んでいます。
ConcurrentHashMap およびJava.util.concurrent
パッケージは、複数のスレッドでHashMapを使用する場合に言及する必要があります。これは標準Javaの一部であるため、小さなメモリフットプリントが保証されます。
「効率的」をどのように定義するかに依存します。
すべてのデータ構造には、読み取り、書き込み、反復、メモリフットプリントなどの独自のBig-Oh動作があります。1つのライブラリ内のリンクリストは、他のライブラリと同じである可能性があります。そして、ハッシュマップは、リンクリストO(n)よりもO(1))を読む方が高速です。
しかし、「最も便利な無料Javaライブラリ?」という質問に対する答えを読んだとき、私はtroveがほとんど言及されていないことに気付きました。
これは「最も効率的」とは思えません。私には「最も人気がある」ように聞こえます。
ほんの少しのフィードバック-私はそれを聞いたことがなく、私はそれを使った人を知りません。 JDK、Google、またはApache Commonsに組み込まれているコレクションは、よく知られています。
ハッシュテーブルに数百万のレコードを格納する場合、メモリの問題に遭遇する可能性があります。これは、たとえば230万のStringオブジェクトを含むマップを作成しようとしたときに起こりました。 BerkeleyDB を使用しました。これは非常に成熟しており、パフォーマンスも良好です。コレクションAPIをラップするJava APIがあるため、メモリフットプリントがほとんどない任意の大きなマップを簡単に作成できます。ただし、ディスクに保存されるため、アクセスは遅くなります。
フォローアップの質問:不変のコレクションのための、きちんとした(そして効率的な)、よく維持されたライブラリはありますか? Clojureにはこれに対する優れたサポートがあり、Javaにも同様のものがあればいいと思います。