web-dev-qa-db-de.com

Was ist die effizienteste Java Collections-Bibliothek?

Was ist die effizienteste Java Sammlungsbibliothek?

Vor ein paar Jahren habe ich viele Java ausgeführt und hatte damals den Eindruck, dass trove die beste (effizienteste) Java Collections-Implementierung ist . Aber als ich die Antworten auf die Frage " Nützlichste freie Java Bibliotheken? " las, bemerkte ich, dass Schatz kaum erwähnt wird. Welche Java Collections-Bibliothek ist jetzt am besten?

UPDATE: Zur Verdeutlichung möchte ich vor allem wissen, welche Bibliothek ich verwenden soll, wenn ich Millionen von Einträgen in einer Hash-Tabelle usw. speichern muss (brauche eine kleine Laufzeit und Speicherbedarf).

135
Frank

Nach der Prüfung sieht es so aus, als ob Trove nur eine Bibliothek von Sammlungen für primitive Typen ist - es ist nicht so, als würde sie den normalen Sammlungen im JDK eine Menge Funktionalität hinzufügen.

Persönlich (und ich bin voreingenommen) liebe ich Guava (einschließlich des früheren Google Java Collections-Projekts). Es macht verschiedene Aufgaben (einschließlich Sammlungen) viel einfacher, in Ein zumindest einigermaßen effizienter Weg: Da Auflistungsvorgänge in meinem Code (meiner Erfahrung nach) selten einen Engpass darstellen, ist dies "besser" als eine Auflistungs-API, die möglicherweise effizienter ist, meinen Code jedoch nicht als lesbar darstellt.

Angesichts der Tatsache, dass die Überschneidung zwischen Trove und der Guave so gut wie Null ist, könnten Sie vielleicht in einer Sammlungsbibliothek klären, wonach Sie tatsächlich suchen.

72
Jon Skeet

Die Frage ist (jetzt), wie viele Daten in einer Karte gespeichert werden können, die mit primitiven Typen wie int dargestellt werden können. Einige der Antworten hier sind meiner Meinung nach sehr irreführend. Mal sehen warum.

Ich habe den Benchmark von trove geändert, um sowohl die Laufzeit als auch den Speicherverbrauch zu messen. Ich habe auch PCJ zu diesem Benchmark hinzugefügt, der eine weitere Auflistungsbibliothek für primitive Typen ist (ich verwende diese häufig). Der 'offizielle' Referenzindex vergleicht IntIntMaps nicht mit Java Collection's Map<Integer, Integer>, Wahrscheinlich wird Integers gespeichert und ints ist nicht dasselbe von Ein Benutzer, der sich nicht für dieses technische Detail interessiert, möchte Daten, die mit ints darstellbar sind, effizient speichern.

Zuerst der relevante Teil des Codes:

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();
     }

Ich gehe davon aus, dass die Daten als primitive ints vorliegen, was vernünftig erscheint. Dies impliziert jedoch eine Laufzeitstrafe für Java util aufgrund des Auto-Boxing, das für die primitiven Collections-Frameworks nicht erforderlich ist.

Die Laufzeitergebnisse (natürlich ohne gc() Aufrufe) unter WinXP, jdk1.6.0_10:

 100000 Put-Operationen 100000 enthält Operationen 
 Java-Sammlungen 1938 ms 203 ms 
 Bereich 234 ms 125 ms 
 PCJ 516 ms 94 ms 

Dies mag bereits drastisch erscheinen, ist jedoch nicht der Grund, ein solches Framework zu verwenden.

Der Grund ist die Speicherleistung. Die Ergebnisse für eine Karte mit 100000 int Einträgen:

 Java-Sammlungen schwanken zwischen 6644536 und 7168840 Byte 
 Überschreiten 1853296 Byte 
 Pcj 1866112 Byte 

Java Collections benötigt mehr als das Dreifache des Speichers im Vergleich zu den primitiven Collection-Frameworks. Das heißt Sie können dreimal so viele Daten im Speicher behalten, ohne auf die Festplatte zurückzugreifen IO, die die Laufzeitleistung um Größenordnungen senkt. Und das ist wichtig. Lesen Sie Hochskalierbarkeit , um herauszufinden, warum.

Meiner Erfahrung nach ist ein hoher Speicherverbrauch das größte Leistungsproblem bei Java, was natürlich auch zu einer schlechteren Laufzeitleistung führt. Primitive Collection Frameworks können hier wirklich helfen.

Also: Nein, Java.util ist nicht die Antwort. Und das "Hinzufügen von Funktionalität" zu Java - Sammlungen ist nicht der Punkt, an dem nach Effizienz gefragt wird. Auch die modernen JDK-Sammlungen tun dies nicht "übertreffen sogar die spezialisierten Trove-Kollektionen".

Haftungsausschluss: Der Benchmark hier ist bei weitem nicht vollständig und auch nicht perfekt. Es soll den Punkt nach Hause fahren, den ich in vielen Projekten erlebt habe. Primitive Sammlungen sind nützlich genug, um fischartige APIs zu tolerieren - , wenn Sie mit vielen Daten arbeiten.

103
the.duckman

Ich weiß, dass dies ein alter Beitrag ist und es hier eine Menge Antworten gibt. Die obigen Antworten sind jedoch oberflächlich und in Bezug auf den Vorschlag einer Bibliothek zu vereinfacht. Es gibt keine Bibliothek, die in den verschiedenen hier vorgestellten Benchmarks gut abschneidet. Die einzige Schlussfolgerung, die ich daraus ziehe, ist, wenn Sie sich für Leistung und Gedächtnis interessieren und sich speziell mit primitiven Typen befassen, ist es mehr als lohnenswert, sich die nicht-jdk-Alternativen anzusehen.

Hier finden Sie eine fundiertere Analyse in Bezug auf die Benchmark-Mechanik und die abgedeckten Bibliotheken. This ist ein Thread in der Mahout Dev List.

Die abgedeckten Bibliotheken sind

  • HPPC
  • Schatz
  • FastUtil
  • Mahout (Colt)
  • Java-Sammlungen

Update Juni 2015 : Leider sind die ursprünglichen Benchmarks nicht mehr verfügbar und zudem etwas veraltet. Here ist ein relativ neuer Benchmark (Januar 2015), der von jemand anderem erstellt wurde. Es ist nicht so umfassend und enthält auch keine interaktiven Erkundungstools wie der ursprüngliche Link.

45
smartnut007

Wie andere Kommentatoren bemerkt haben, wirft die Definition von "effizient" ein breites Netz. Jedoch hat noch niemand die Javolution Bibliothek erwähnt.

Einige der Highlights:

  • Javolution-Klassen sind schnell, sehr schnell (z. B. Einfügen/Löschen von Text in O [Log (n)] anstelle von O [n] für Standard-StringBuffer/StringBuilder).
  • Alle Javolution-Klassen sind echtzeitfähig und haben ein sehr deterministisches Verhalten (im Mikrosekundenbereich). Außerdem ist Javolution (im Gegensatz zur Standardbibliothek) RTSJ-sicher (kein Speicherverlust oder Speicherverlust bei Verwendung mit Java Real-Time-Erweiterung)).
  • Die Echtzeit-Erfassungsklassen von Javolution (Karte, Liste, Tabelle und Menge) können anstelle der meisten Standarderfassungsklassen verwendet werden und bieten zusätzliche Funktionen.
  • Die Javolution-Sammlungen bieten Parallelitätsgarantien, um die Implementierung paralleler Algorithmen zu vereinfachen.

Die Javolution-Distribution enthält eine Benchmark-Suite, mit der Sie sehen können, wie sie mit anderen Bibliotheken/den integrierten Sammlungen verglichen werden.

19
sstock

Einige zu berücksichtigende Sammlungsbibliotheken:

Ich würde in erster Linie nach der JDK-Sammlungsbibliothek greifen. Es deckt die häufigsten Dinge ab, die Sie tun müssen, und steht Ihnen offensichtlich bereits zur Verfügung.

Google Collections ist wahrscheinlich die beste hochwertige Bibliothek außerhalb des JDK. Es ist stark genutzt und gut unterstützt.

Apache Commons Collections ist älter und leidet ein bisschen unter dem Problem "zu viele Köche", hat aber auch eine Menge nützlicher Dinge.

Trove hat sehr spezielle Sammlungen für Fälle wie primitive Schlüssel/Werte. In diesen Tagen stellen wir fest, dass auf modernen JDKs und mit den Java= 5+ Sammlungen und gleichzeitigen Anwendungsfällen die JDK-Sammlungen sogar die spezialisierten Trove-Sammlungen übertreffen.

Wenn Sie wirklich häufige Nebenläufigkeitsanwendungen haben, sollten Sie sich auf jeden Fall Dinge wie die NonBlockingHashMap in der High-Scale-Bibliothek ansehen, die keine Sperren enthält und die ConcurrentHashMap verwenden kann, wenn Sie den richtigen Anwendungsfall dafür haben.

15
Alex Miller

Informationen zum Speichern von Millionen von String in einer Karte finden Sie unter http://code.google.com/p/flatmap

6
akuhn

Java.util

Entschuldigen Sie die offensichtliche Antwort, aber für die meisten Verwendungszwecke ist die Standardeinstellung Java Collections mehr als ausreichend.

6
Yuval Adam

Ich bin Entwickler von Happy-Collections aus Happy-Collections auf Source-Forge

  1. Eventbasierte Sammlungen
  2. Nicht änderbar
  3. SortedList
  4. Zwischenspeicher
4

Trove bietet einige Vorteile.

  • bei geringerem Speicherbedarf werden keine Map.Entry-Objekte verwendet
  • sie können Hash-Strategien anstelle von Schlüsseln für Maps verwenden. Dies spart Speicherplatz und bedeutet, dass Sie nicht jedes Mal einen neuen Schlüssel definieren müssen, wenn Sie ein Objekt in einem neuen Satz seiner Attribute zwischenspeichern möchten
  • es hat primitive Sammlungstypen
  • denke, es hat eine Form von internen Iterator

Trotzdem wurde seit dem Schreiben von trove viel getan, um die jdk-Sammlungen zu verbessern.

Es sind die Hashing-Strategien, die es für mich attraktiv machen ... Google für Schatz und lesen Sie deren Übersicht.

3
paul

ConcurrentHashMap sowie das Java.util.concurrent package sollte erwähnt werden, wenn Sie die HashMap in mehreren Threads verwenden möchten. Es wird ein geringer Speicherbedarf angenommen, da dies Teil des Standard-Java ist.

3

Kommt darauf an, wie wir "effizient" definieren.

Jede Datenstruktur hat ein eigenes Big-Oh-Verhalten zum Lesen, Schreiben, Wiederholen, Speichern usw. Eine verknüpfte Liste in einer Bibliothek ist wahrscheinlich dieselbe wie jede andere. Und eine Hash-Map ist schneller zum Lesen von O(1) als eine verknüpfte Liste O (n).

Aber als ich die Antworten auf die Frage "Nützlichste freie Java Bibliotheken?" Las, bemerkte ich, dass die Fundgrube kaum erwähnt wird.

Das klingt nicht nach "effizientesten". Es klingt für mich nach "am beliebtesten".

Nur ein paar Rückmeldungen - ich habe noch nie davon gehört und kenne niemanden, der es benutzt hat. In JDK, Google oder Apache Commons integrierte Sammlungen sind mir bekannt.

3
duffymo

Wenn Sie Millionen von Datensätzen in einer Hash-Tabelle speichern möchten, können Speicherprobleme auftreten. Dies ist mir passiert, als ich zum Beispiel versucht habe, eine Map mit 2,3 Millionen String-Objekten zu erstellen. Ich habe BerkeleyDB gewählt, das sehr ausgereift ist und eine gute Leistung erbringt. Sie haben eine Java API, die die Collections API umschließt, sodass Sie leicht beliebig große Maps mit sehr wenig Speicherbedarf erstellen können. Der Zugriff ist jedoch langsamer (da sie auf der Festplatte gespeichert sind).

Folgefrage : Gibt es eine anständige (und effiziente), gut gepflegte Bibliothek für unveränderliche Sammlungen? Clojure hat dafür eine hervorragende Unterstützung, und es wäre schön, etwas Ähnliches für Java zu haben.

2
fred-o