Ich habe eine Datei bestehend aus 7.6M Zeilen. Jede Zeile hat die folgende Form: A, B, C, D, wobei B, C, D Werte sind, die zur Berechnung einer Bedeutungsebene für A verwendet werden, die eine String-Kennung ist, die für jede Zeile eindeutig ist. Mein Ansatz:Java hashmap vs hashset Leistung
private void read(String filename) throws Throwable {
BufferedReader br = new BufferedReader(new FileReader(filename));
Map<String, Double> mmap = new HashMap<>(10000000,0.8f);
String line;
long t0 = System.currentTimeMillis();
while ((line = br.readLine()) != null) {
split(line);
mmap.put(splitted[0], 0.0);
}
long t1 = System.currentTimeMillis();
br.close();
System.out.println("Completed in " + (t1 - t0)/1000.0 + " seconds");
}
private void split(String line) {
int idxComma, idxToken = 0, fromIndex = 0;
while ((idxComma = line.indexOf(delimiter, fromIndex)) != -1) {
splitted[idxToken++] = line.substring(fromIndex, idxComma);
fromIndex = idxComma + 1;
}
splitted[idxToken] = line.substring(fromIndex);
}
wo der Blindwert 0,0 wird für „Profilieren“ Zwecke eingesetzt und gespaltet ist ein einfaches String-Array für die Klasse definiert ist. Ich habe anfangs mit der split() - Methode von String gearbeitet, fand aber, dass das oben genannte schneller ist.
Wenn ich den obigen Code ausführen, dauert es 12 Sekunden, um die Datei zu analysieren, was waaaay mehr ist, als ich denke, es sollte dauern. Wenn ich z. B. die HashMap durch einen Vektor von Strings ersetze und nur den ersten Eintrag von jeder Zeile nehme (dh ich gebe keinen zugehörigen Wert ein, da dieser konstant amortisiert sein soll), kann die gesamte Datei in weniger als eingelesen werden 3 Sekunden.
Dies deutet darauf hin, dass (i) es gibt viele Kollisionen in der HashMap (Ich habe versucht, die Anzahl der Größen durch Vorabzuweisung der Größe und Einstellung der Auslastung Faktor zu minimieren) oder (ii) der HashCode() Funktion ist irgendwie langsam. Ich bezweifle es (ii), denn wenn ich ein HashSet verwende, können die Dateien in weniger als 4 Sekunden eingelesen werden.
Meine Frage ist: Was könnte der Grund sein, dass die HashMap so langsam funktioniert? Reicht der HashCode() für Karten dieser Größe nicht aus, oder gibt es etwas, was ich übersehen habe?
Versuchen Sie '0.0' Dummy-Wert mit einem gewissen static final konstant zu ersetzen. '0.0' wird ersetzt durch' Double.valueOf', welches jedes Mal ein neues Objekt erzeugt. Und im 'HashSet' wird nur ein vorbelegtes Dummy-Objekt verwendet. Ich bin nicht sicher, dass das der Grund ist, aber es kann sein – esin88
Das letzte Element von 'splitted []' wird immer die gesamte Zeile enthalten. Das ist nicht was du willst. – EJP
'HashSet' wird intern durch' HashMap' unterstützt, der einzige Unterschied ist das automatische Boxen Ihres Dummy '0.0'. – bashnesnos