Key/Value Table in Klasse einlesen

Diskutiere Key/Value Table in Klasse einlesen im Allgemeine Java-Themen Bereich.
Bitte aktiviere JavaScript!
Thallius

Thallius

Hi,

ich habe eine SQL settings Tabelle mit den Columns key und Value. Diese kann ich natürlich sehr leicht in eine Map einlesen. Das Problem ist, das die Werte in einer hoch komplexen rechenintensiven routine sehr oft benutzt werden. Wenn ich dort jedesmal die Map nach dem richtigen Wert durchsuchen lasse kostet mich das einfach zu viel Performance.

Ich würde nun gerne eine Klasse erstellen mit festen Variablen für jeden key den ich in dieser Routine brauche und die Werte direkt zuweisen. Klar kann ich das von Hand machen indem ich jedem Attribut das entsprechende Value aus der Map zuweise.

Aber vielleicht gibt es hier ja auch einen schöneren Weg?

Also z.B.

Map:

"value1" => 100
"value2" => 200
"value3" => 300

Entsprechende Klasse

Code:
public class settings
{
    public value1, value2, value3;
}
Gruß

Claus
 
L

LimDul

ich habe eine SQL settings Tabelle mit den Columns key und Value. Diese kann ich natürlich sehr leicht in eine Map einlesen. Das Problem ist, das die Werte in einer hoch komplexen rechenintensiven routine sehr oft benutzt werden. Wenn ich dort jedesmal die Map nach dem richtigen Wert durchsuchen lasse kostet mich das einfach zu viel Performance.
Hast du es gemessen? Ich wage das zu bezweifeln, dass das ein Performance Problem ist. Eine HashMap sollte O(1) beim Zugriff haben.
 
Thallius

Thallius

Hast du es gemessen? Ich wage das zu bezweifeln, dass das ein Performance Problem ist. Eine HashMap sollte O(1) beim Zugriff haben.
Das must du mir erklären. Bei jedem Zugriff auf die Map über einen Key muss die ganze Map nach dem Key abgesucht werden. Also ganz viele String compares bevor das Ergebnis gefunden wird wenn es das letzte Element in der Map ist.
 
T

thecain

Eine Map funktioniert meist mit einem Hash. Da wird der korrekte Bucket und somit das Element direkt gefunden. Verglichen wird dann nur noch bei Hash Kollisionen
 
Thallius

Thallius

Ein Hash ist doch auch nichts anderes als ein String und somit wieder jede Menge Vergleiche. Und selbst wenn nicht, dann muss ich trotzdem durch die Liste der Einträge gehen um den richtigen zu finden.
 
H

httpdigest

Was hält dich denn davon ab, einfach für die jeweilige Berechnung die benötigten Werte einmal aus der Map zu lesen und in z.B. Instanzvariablen zu cachen, falls dir die wenigen vermutlich ein-zweistelligen Nanosekunden Zugriffszeiten für eine HashMap zu viel sind?
Java:
import java.util.Map;
public class HochperformanteRoutine {
  // Alle benötigten Werte
  private final int value1;
  private final int value2;
  private final int value3;
  public HochperformanteRoutine(Map<String, Integer> alleWerte) {
    this.value1 = alleWerte.get("value1");
    this.value2 = alleWerte.get("value2");
    this.value3 = alleWerte.get("value3");
  }
  public double berechneUnfassbarKomplexeFunktion() {
    // hier kannst du natürlich this.value1..value3 verwenden.
  }
}
oder einfach in der Berechnungsmethode die Map benutzen, darauf einmal die Werte auszulesen und in lokale Methodenvariablen zu speichern, die du dann in der Berechnung verwendest...
 
Thallius

Thallius

Was hält dich denn davon ab, einfach für die jeweilige Berechnung die benötigten Werte einmal aus der Map zu lesen und in z.B. Instanzvariablen zu cachen, falls dir die wenigen vermutlich ein-zweistelligen Nanosekunden Zugriffszeiten für eine HashMap zu viel sind?
Java:
import java.util.Map;
public class HochperformanteRoutine {
  // Alle benötigten Werte
  private final int value1;
  private final int value2;
  private final int value3;
  public HochperformanteRoutine(Map<String, Integer> alleWerte) {
    this.value1 = alleWerte.get("value1");
    this.value2 = alleWerte.get("value2");
    this.value3 = alleWerte.get("value3");
  }
  public double berechneUnfassbarKomplexeFunktion() {
    // hier kannst du natürlich this.value1..value3 verwenden.
  }
}
oder einfach in der Berechnungsmethode die Map benutzen, darauf einmal die Werte auszulesen und in lokale Methodenvariablen zu speichern, die du dann in der Berechnung verwendest...
Das ist meine aktuelle Methode. Sieht bei ca. 20 Werten aber eben scheiße aus. Deshalb fragte ich nach einer schöneren Methode.

Und Java Programmierer sind glaube ich alle komplett versucht was Performance angeht. Glaubt ihr wirklich der Zugriff auf eine Hashmap würde ein paar nanosekunden dauern? Und selbst wenn ist es immer noch 1000x langsamer als ein einfacher Zugriff auf eine Speicheradresse wenn der Wert in einer Instanzvariablen liegt.
 
H

httpdigest

Und selbst wenn ist es immer noch 1000x langsamer als ein einfacher Zugriff auf eine Speicheradresse wenn der Wert in einer Instanzvariablen liegt.
Nein. Statt unbelegte Vermutungen anzustellen, solltest wie @LimDul sagte, testen.... Nimm z.B. JMH und teste es... du wirst feststellen, dass dies nicht so ist.

Das ist meine aktuelle Methode. Sieht bei ca. 20 Werten aber eben scheiße aus. Deshalb fragte ich nach einer schöneren Methode.
Naja... wie anders kann es denn aussehen? Du musst ja schließlich immer noch die Variablen explizit deklarieren und explizit zuweisen..
 
H

httpdigest

Vielleicht mal als Beweis, dass eine HashMap seeeeehr seeeeeehr schnell ist:
Java:
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
public class Bench {
    private Map<String, Integer> map = new HashMap<>();
    private int instanceVariable;
    @Setup
    public void setup() {
        this.instanceVariable = 3;
        this.map.put("hello", 3);
    }
    @Benchmark
    public int getFromMap() {
        return map.get("hello");
    }
    @Benchmark
    public int getFromInstanceVariable() {
        return instanceVariable;
    }
    public static void main(String[] args) throws Exception {
        Options opt = new OptionsBuilder().include(Bench.class.getName()).forks(1).build();
        new Runner(opt).run();
    }
}
Result:
Code:
Benchmark                      Mode  Cnt  Score   Error  Units
Bench.getFromInstanceVariable  avgt   10  1,728 ± 0,003  ns/op
Bench.getFromMap               avgt   10  4,308 ± 0,016  ns/op
Ein Zugriff auf eine Instanzvariable ist also gerademal lächerliche 1.5x schneller als ein HashMap.get() Zugriff. Rechnung: (4.308 - 1.728) / 1.728

EDIT: Okay, und jetzt noch mit einer Map mit 1000 Einträgen:
Java:
...
@Setup
public void setup() {
    instanceVariable = 3;
    for (int i = 0; i < 1000; i++)
        map.put("value" + i, i);
}
@Benchmark
public int getFromMap() {
    return map.get("value277");
}
...
Ergebnis:
Code:
Benchmark                      Mode  Cnt  Score   Error  Units
Bench.getFromInstanceVariable  avgt   10  1,730 ± 0,020  ns/op
Bench.getFromMap               avgt   10  6,868 ± 0,090  ns/op
Also gerade mal fast nur 3x schneller.
 
Zuletzt bearbeitet:
L

LimDul

Das ist meine aktuelle Methode. Sieht bei ca. 20 Werten aber eben scheiße aus. Deshalb fragte ich nach einer schöneren Methode.

Und Java Programmierer sind glaube ich alle komplett versucht was Performance angeht. Glaubt ihr wirklich der Zugriff auf eine Hashmap würde ein paar nanosekunden dauern? Und selbst wenn ist es immer noch 1000x langsamer als ein einfacher Zugriff auf eine Speicheradresse wenn der Wert in einer Instanzvariablen liegt.
Deine Zahl, wie schon gezeigt, ist grober Unfug. Bei den ganzen Abstraktationsschichten und Optimierungen die dazwischen liegen, (Java Hotspot, Prozessor etc.) sind solche Aussagen schlicht falsch. Und generell gilt: Wer bei Performance Fragen keine Messungen vorgenommen hat, liegt mit nahezu 100% mit seinen Vermutungen daneben.

Es gibt ein schönes Zitat von Donald Knuth:
The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.”
Und da ist viel wahres dran. Wenn du dein Programm schneller bekommen willst, miss welche Stellen lang brauchen. Und optimiere da. Du wirst mit Sicherheit feststellen, selbst wenn dein Zugriff auf Instanzvariablen 10x schneller ist - dein Programm wird vielleicht nur 0,1% schneller - wenn überhaupt, weil das eine Stelle ist die Gegensatz zum Rest überhaupt nicht ins Gewicht fällt.

Es gibt mit Sicherheit Gründe es anders zu gestalten, als die Daten als reine Key/Value Paare abzulegen - aber Performance ist keins davon.
 
A

AndiE

Für mich wäre es eine Frage der Lesbarkeit. Und da würde ich erstmal das mathematische Modell so anlegen, dass es durchschaubar ist, also mit sprechenden Variablen. (breite, hoehe usw. statt value1, value2 ). Ich halte auch werte.get("hooehe")*werte.get("breite") ebenso für wenig nachvollziehbar wie "werte[1]*werte[2]", oder werte[BREITE]*werte[HOEHE], wobwi ich "BREITE =1 und HOEHE=2 vorher deklariert habe.

Daher würde ich für den nicht so schönen aber praktischen Weg stimmen, die Variablen händisch zuzuweisen.
 
Thema: 

Key/Value Table in Klasse einlesen

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben