2016-07-27 9 views
0

Nicht das erste Mal, dass ich auf dieses Problem gestoßen bin.Maximierung der Java-Anwendung (Vanille Datenverarbeitung) Leistung

Ich optimiere meinen Scala/Java-Code, indem ich Aufnahmen von Flight Recorder in Java Mission Control anschaue. Sehen Sie sich die heißesten Methoden und Speicherzuordnungen an, und schließlich wird die Anwendung 50x schneller oder 3x schneller ausgeführt.

Sobald ich an diesen Punkt komme, ist die CPU-Auslastung 60-90% und die Speicherauslastung ist beispielsweise 2 GB von der maximalen 4 GB Heap. Aber ich denke, ich könnte viel mehr Geschwindigkeit herausdrücken.

Eigenschaften:

  • Einzel Thread-Verarbeitung, eine einzelne Datei aus dem Dateisystem zu lesen.
  • Sequenzielles Lesen, wo die Lesegeschwindigkeit des Dateisystems 1 GB/s beträgt, aber die Verarbeitung ist so langsam wie 5 MB/s (Verzweigung, Statusmaschinen usw.).
  • Minimierte die Müllsammlungen, wo ich konnte.
  • Keine ausgefallenen Bibliotheken, nur reiner JVM-Code.

-Code sieht wie folgt grob (in Pseudo-Code):

for line in file // using an iterator which would call into a file 
    result = process_line(line) 
    state = state.process(result) 
    if state.emits: 
    println(state.result) 

In einer Anwendung Ich habe folgende heißesten Methoden:

scala.collection.immutable.HashMap$HashTrieMap.getO(Object, Int, Int) 6.75% 
java.io.BufferedInputStream.read() 4.97% 

In einem anderen (dies ist aus der Spitze von meinem Kopf):

(some sort of garbage collection process) 9% 
...  7% 

Ist es immer noch wert opt diese imitieren? Ich habe es versucht und habe sehr wenig Leistungsverbesserung für viel komplexeren Code bekommen.

Wohin soll ich als nächstes schauen?

Sollte ich erwägen, process_line() in einem Thread zu tun und dann den Zustand in einem anderen Thread zu iterieren, um den Kontextwechsel zu minimieren? Vielleicht verlangsamt das die Dinge?

Was ist der richtige Weg? Ich möchte das Problem selbst noch nicht parallelisieren.

+1

Ich würde konzentrieren, wo Sie die meiste Zeit mit CPU verbringen und sehen, ob Sie es optimieren oder die Arbeit an einen anderen Thread übergeben können. I.e. Sie gehen in die richtige Richtung, Sie müssen weiter optimieren. –

+0

Ich habe die Frage aktualisiert, um etwas mehr Details einzubeziehen. Es gibt keine "heißeste" Methode, es gibt eine Menge verschiedener Pakete, die ungefähr die gleiche Menge an CPU verwenden. –

+1

Ich wäre verdächtig auf eine sortierte Sammlung wie Sie haben und sehen, ob Sie den Code ohne es schreiben können. BufferedInputStream.read() sollte nicht so teuer sein, wie es im Idealfall das Blockieren von Bytes zu einer Zeit lesen sollte, aber es hängt davon ab, warum Sie dies tun. Ich würde sehen, wie viele Methoden sind "Noise" esp Sammelvorgänge, und nicht die Kernlogik von was Ihre Anwendung tut. –

Antwort

0

Ich würde den Leser parallelisieren.

Wenn sich die Daten auf der Festplatte befinden, können Sie einen Thread erstellen, der Daten von einem Datenträger in Blöcken und einem anderen, der ihn verarbeitet, liest. Dies ist übrigens, wie Java Mission Control 4 Aufzeichnungsdateien liest. Oder Sie könnten Java Mission Control 5 verwenden, das eine RandomAccessFile verwendet, die es aus mehreren Threads liest und dann das Ergebnis zusammenfügt.