Ist Java wirklich so eine lahme Krücke

  • Antworten:15
  • Bentwortet
Andreas Weichert
  • Forum-Beiträge: 287

03.10.2012, 13:43:46 via Website

Hallo !
Hab enorme Performanceproblem bei meine App. Es geht darum, das ich strukturierte Daten aus einem Textfile lesen will.
Da ich eigentlich C++ Programmierer bin und erst seit 4 Monaten mich mit Java befasse, habe ich erstmal analog C++
entwickelt und die Strukturen übernommen.
Ich lese Zeilenweise aus und interpretiere dann. Ich verwenden.
StringBuilder String trim substring und Scanner hasnext relativ häufig.
Um eine String zu parsen erzeuge ich ein Scanner Scanner sc = new Scanner(String); Das mache ich ziemlich häufig.

Habs im Emulator laufen lassen um ev. langsame Stellen Zeilenweise zu finden. Brache aber nix. Das Ganze scheint alles
irgendwie langsam zu laufen.
In C++ läuft analoger code super - praktisch nicht messbar (unter einer ms)

Ist Java wirklich 1000 - 10000 mal langsamer als C++ ?
Wie ist Eure Erfahrung?

Antworten
Andy N.
  • Forum-Beiträge: 3.112

03.10.2012, 14:29:37 via Website

Bei so was sollte es keinen Unterschied bezüglich Geschwindigkeit geben. Lädst Du eventuell die komplette Datei in den RAM?

Antworten
Florian B.
  • Forum-Beiträge: 284

03.10.2012, 14:31:48 via Website

Also braucht der Java Code ca. 1-10 Sekunden? Ich würde die Laufzeit der einzelnen Methoden durchmessen, dann solltest du recht schnell herausfinden wo es hakt.

— geändert am 03.10.2012, 14:39:26

Antworten
Andreas Weichert
  • Forum-Beiträge: 287

03.10.2012, 15:05:17 via Website

Also ich habe eine wenig übertrieben - in meiner Java-Enttäuschung. Sorry.
Der Code würde in C++ auf dem PC nach meiner Erfahrung praktisch nicht messbar sein. Das meinte ich.

Auf dem Handy natürlich langsamer - würde aber trotzdem nicht in Gewicht fallen.

Ich lade ca. 50 Zeilen Textfile ein - ist letztendlich so eine Art ini-Struktur
Variable = 7
Variable1 = "Hallo"
etc.
Das dauert 0.5 Sec. Mit 20 files also 10 Sec. Das kann ich dem Anwender und mir nicht zumuten.

Ich lade das file nicht komplett ins RAM ein. Ich leste mit

Scanner sc = new Scanner(new FileReader(FN));
String line = sc.nextLine();
Dann splitte ich bei "=" - suche den VariableNamen in einer List - nehme den rechte Teil und fülle damit die Variable.
Da der Variablenwert i.a. komplizierter sein kann, scanne ich den nochmal mit z.B.
Scanner sc = new Scanner(RechterTeil);
sc.hasNext(); int i = sc.NextInt();

Das ist so im Prinzip der Ablauf.
Es wird einiges mit new erzeugt. Das dürfte aber trotz Java doch nicht so lange dauern.

Debuggen ist schwierig muß dann dann wohl Code einfügen der die einzelen Zeiten mißt.

Antworten
Carsten M.
  • Forum-Beiträge: 33.204

03.10.2012, 15:38:28 via App

Auf welchem Gerät hast Du das getestet?

Herzliche Grüße

Carsten

Ich komm' mir langsam vor wie jemand, der ich bin // #cäthe

Antworten
Andy N.
  • Forum-Beiträge: 3.112

03.10.2012, 15:39:31 via Website

Solche Funktionen laufen auch bei Java nativ, also denke ich nicht, dass es an Java liegt.
Spricht etwas dagegen die Struktur der Textfile zu ändern, zB in ein JSON Format? JSON die schnellste und beste Möglichkeit Daten aus einem Textfile zu holen.

Antworten
Florian B.
  • Forum-Beiträge: 284

03.10.2012, 15:49:10 via Website

Ja Debuggen wird nichts nützen, ich würde nen Timer mitlaufen lassen und mir die Zeiten loggen lassen. Dann siehst du am schnellsten wo Zeit gelassen wird. So ist es gerade nur ein Rumgerate.

— geändert am 03.10.2012, 15:49:28

Antworten
Carsten M.
  • Forum-Beiträge: 33.204

03.10.2012, 15:49:15 via App

Hmm, kommt mir sehr lang vor...

10 Sekunden dauert es bei mir gerade mal, wenn ich 6000 Grafiken aus einer SQL Datei lese und in Image views darstelle...

Herzliche Grüße

Carsten

Ich komm' mir langsam vor wie jemand, der ich bin // #cäthe

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

03.10.2012, 15:58:14 via Website

Achte darauf das du nicht im Loop haufenweise 'teure' Objecte erzeugst wie die Scanner Klasse z.b.

PS: Mit C++ auf dem PC solltest du deinen Code nicht vergleichen. Es gibt da mehr als genug Benchmarks die nicht das gegenteil beweisen!

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Steve Saev
  • Forum-Beiträge: 8

03.10.2012, 17:27:29 via Website

Hallo Andreas,

es ist etwas schwer auf deine Frage ein genaue Antwort zu geben ohne den Code etwas näher zu kennen.

Grundsätzlich aber arbeiten JVMs wie Dalvik mit JIT (just in time), was sehr effizienten nativen Code erzeugt. Gerade in solchen Schleifen greift diese Optimierung sehr gut (was übrigens in manchen Fällen tatsächlich zu Geschwindigkeitsvorteilen gegenüber C/C++ führt).

Es gibt aber Sachen auf die man besonders gut achten muss in Java (naja die in C/C++ eigentlich auch Performance-Killer wären), nämlich die Objekt-Generierung. Macht man das zu exzessiv in einer Schleife kann das zu extremer Verlangsamung führen. Ich benutze persönlich das Scanner-Objekt nicht so oft und habe daher nicht die Erfahrung, ob und wie es sich auf die Performance auswirkt - aber es wäre ein mögliche Quelle für dein Problem.

Fazit: Java ist nicht langsam - oft sogar verdammt schnell - aber man muss einige Regeln beachten (wie vermutlich in jeder Programmiersprache). Eventuell kannst du etwas mehr von deinem Code posten damit man eventuelle Fallstricke dort erkennen kann.

Grüße,

Steve

Antworten
Andreas Weichert
  • Forum-Beiträge: 287

03.10.2012, 17:48:48 via Website

Vielen Dank für die Tips.
Ich komme irgenwie nicht weiter - es schein keine spezielle langsame Codestelle zu geben - alles ist langsam.
Es summiert sich einfach.
Hier habe ich z.B. den Code um Strings mit maskierten Zeichen aus Dateien (order allg. Streams) zu lesen.
(R hat schon die Daten im RAM - Scanner R = new Scanner(String);

1StringBuilder x;
2 @Override void Stream(Scanner R)
3 {
4 long t1 = Glob.clock();
5 Clear();
6 boolean replace=false;
7 while(R.hasNext())
8 {
9 char c=R.findInLine(".").charAt(0);
10 if(c=='\\')
11 {
12 if(!replace)
13 {
14 replace=true;
15 continue;
16 }
17 x.append('\\');
18 replace=false;
19 continue;
20 }
21 if(replace)
22 {
23 switch(c)
24 {
25 case 'n': x.append('\n'); break;
26 case '\"': x.append('"'); break;
27 }
28 replace=false;
29 continue;
30 }
31 if(c=='"')
32 continue;
33 x.append(c);
34 }
35 long t2 = Glob.clock();
36 Glob.Time1 += t2 - t1;
37
38 }

Der brauch für ca. 0.5 Sec für ca. 50 Aufrufe. Das kann doch nicht sein!?

Antworten
Steve Saev
  • Forum-Beiträge: 8

03.10.2012, 18:00:42 via Website

Hallo nochmal,

ok der Code sieht auf den ersten Blick nicht so schlimm aus... auf jeden Fall sehe ich auf den ersten Blick nicht wo dort eine halbe Sekunde verloren geht.

Unklar für mich ist der Aufruf von "clear()" -> was macht das? Das wird auf jeden Fall für jede Zeile deiner Datei aufgerufen.
Weiter (für mich) unklar ist die Verwendung von Scanner und dessen Auswirkung auf die Performance hat. Meine Analyse sagt mir, dass nur folgende Code-Stellen langsam sein könnten:

"Clear();"
"R.hasNext()"
"R.findInLine( "." )"

Alles Andere fällt unter Peanuts! ;)

Ach ja... du hast übrigens einen sehr schönen namen für dein Argument "Scanner R" gewählt! ;) In einem Android-Programm doppelt schlecht, da automatisch eine Klasse mit dem Namen "R" generiert wird, die dir Zugriff auf deine Resourcen gewährt und es hier zu einem Missverständnis führen kann. Da ich auch in C/C++ (für Windows) programmiert habe, verstehe ich die Namensgebung. Aber in Java gibt es die Konvention Variablen und Argumente mit einem Kleinbuchstaben zu beginnen. Gut hilft dir nicht bei deinem Problem, aber wollte ich nur mal erwähnt haben! ;)

Grüße,

Steve

Antworten
Andreas Weichert
  • Forum-Beiträge: 287

03.10.2012, 18:28:37 via Website

Clear ist nur x = new StringBuilder();
Ja ja die Namengebung.
Einige Programmierer sagen das schwierigste am Programmieren überhaupt ist es sich immer wieder neue Namen auszudenken. :grin:
Habe schon manchmal eine Stunde mit meine Kollegen diskutiert wie wir das nun nenne wollen.

R für Read ist für Android wirklich nicht gut - gebe ich zu.

Mit der Groß/Klein-schreibung habe ich schon erwarte das ich von der Java-Gemeinde deshalb getadelt werden.

Ich entwickele seit ca. 20 Jahren in C++ und habe mir damals eine Konvention ausgesucht, an die ich mich strikt halte.
Teilweise habe ich auch von Borland was über nommen. Meine Typen fangen immmer mit T and TString.

Ich muß aber auch noch in der Woche auf der Arbeit programmieren. Wenn ich hier zu Hause andere Konventionen verwende bekomme ich einen Knoten im Gehirn. Insbesonder, da ich dieseben Bezeichner verwende.

Also bitte ich meine Unkonvertionalität zu entschuldigen.:#

Antworten
Andreas Weichert
  • Forum-Beiträge: 287

03.10.2012, 20:50:34 via Website

Also habe herrausgefunden, dass in Java und insbesondere in Android-Java der Scanner totaler Schrott ist:

http://stackoverflow.com/questions/2446805/is-java-util-scanner-that-slow

Das nextInt() nextFloat() etc. ist extrem langsam.
Durch integer.parseInt(Scanner.next()) wirds schon wesentlich schneller. Werdes es morgen überall einbauen.
Dann wird der "TimeSheriff" wesentlich schneller und ich kann endlich neue Funktionen einbauen.

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

03.10.2012, 21:30:58 via Website

StringBuilder kann übrigens wiederverwendet werden. Einfach die #setLength Methode benutzen.

Ebenfalls kannst du eine geeignete capacity im contructor übergeben was bei längeren Strings (<16 meine ich) ein klein wenig
hilft das interne erweitern des char Arrays zu vermeiden.


PS: Wieso sind deine Methoden Groß geschrieben ? In Java ist es üblich diese klein zu schreiben. Also kein #SetLength sonder #setLength.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten