Java vs. C. Performance-Vergleich
-
Also ich kenne ja nicht viel Java-Software, aber das, was ich kenne, was ne UI hat, ist wegen der Langsamkeit fast nie benutzbar. Jetzt macht man in Java natürlich auch keine Anwendungsprogramme, weil es auch einfach sehr hässlich ist.
Man müsste Mal komplexe Serverframeworks vergleichen. Nur wird so was wiederum nicht in C++ programmiert. Aber wenn man zwei solche Umgebungen vergleichen würde, wären die Komplexitäten wohl zu hoch, als dass die Vergleiche vernünftig wären. Und da Java ja produktiv auch für Riesenprodukte eingesetzt werden kann, ist die Performance wohl zwangsläufig in Ordnung.
Und wenn Java nicht für irgendwelche Dinge zu langsam ist, dann ist es eben auch wieder egal, richtig? Mit Java kommt man nur eben nicht an die Systeminterna dran, man kann wahrscheinlich auch nicht die Grafikkarte programmieren (oder muss da was durchreichen, was dann zu viel Zeit kostet), oder? Ohne solche Spielereien verliert man viel Zeit.
-
Steffo schrieb:
Michael E. schrieb:
Auch Javaprogramme, die nicht Swing benutzen, werden als langsam empfunden.
Z. B.?
Man sollte den Spieß umdrehen und nach schnellen Javaprogrammen fragen
Javaprogrammierer, die ich getroffen habe, tendierten alle dazu, auch schon kleine Probleme totzudesignen. Dann hatte man auf einmal ein Dutzend Klassen, wo es eine Handvoll Funktionen auch getan hätten. Klar, dass das auf die Performance geht.
-
Zu der Sache mit dem stack overflow: Bei mir hat sich eclipse schon einige Male mit einer stack overflow exception verabschiedet, so gut scheint das in java also auch nicht gelöst zu sein
-
GorbGorb schrieb:
Zu der Sache mit dem stack overflow: Bei mir hat sich eclipse schon einige Male mit einer stack overflow exception verabschiedet, so gut scheint das in java also auch nicht gelöst zu sein
Das hat den Hintergrund, dass der Stack für gewisse Aufgaben tatsächlich unverzichtbar ist. Z. B. gerade im Bereich Compiler bzw. IDE, wo der Code auf Gültigkeit geprüft werden muss, arbeitet man mit Stackalgorithmen und da können sich natürlich Programmierfehler einschleichen. Aber Arrays werden in Java soweit ich weiss nicht im Stack, sondern im Heap angelegt.
Liebe Grüße
Steffo
-
Steffo schrieb:
Das hat den Hintergrund, dass der Stack für gewisse Aufgaben tatsächlich unverzichtbar ist. Z. B. gerade im Bereich Compiler bzw. IDE, wo der Code auf Gültigkeit geprüft werden muss, arbeitet man mit Stackalgorithmen
Damit ist aber nicht der Stack[TM] gemeint, über den wir hier reden.
-
Michael E. schrieb:
Damit ist aber nicht der Stack[TM] gemeint, über den wir hier reden.
OK, das stimmt. Peinlich.
-
Zum Swing ist mir gerade ein Ideechen gekommen.
Also erstmal halte ich es für unverzichtbar, sich Klassen wie Point, Size, Rectangle und so zu schreiben und sie auch ganz heftig als Übergabeparameter zu benutzen. Ich habe mal ein Testprogramm geschrieben, das fast nichts anderes macht. Es berechnet PI.#include <iostream> using namespace std; class Point{ public: int x; int y; Point(int xx,int yy){ x=xx; y=yy; } }; class Pi{ private: int treffer; int radius; int radiusQuadrat; public: Pi(int r){ radius=r; radiusQuadrat=radius*radius; treffer=0; } void run(){ for(int y=-radius;y<=radius;++y) for(int x=-radius;x<=radius;++x) shoot(Point(x,y)); } void shoot(Point p){ if(p.x*p.x+p.y*p.y<=radiusQuadrat) ++treffer; } double value(){ return double(treffer)/double(radiusQuadrat); } }; int main() { Pi p(10000); p.run(); cout<<p.value()<<'\n'; }
Könnte das mal einer schnell nach Java übersetzen bitte?
-
Ich habe das mal mit bestem Willen portiert, wobei ich von C++ keine Ahnung habe.
Allerdings habe ich mir erlaubt einige Optimierungen nach Java-Art vorzunehmen.public final class Main { public static void main(final String[] args) { final Pi p = new Pi(10000); p.run(); System.out.println(p.value()); } }
public final class Pi { private int treffer; private final int radius; private final int radiusQuadrat; public Pi (final int r){ radius = r; radiusQuadrat = radius*radius; treffer = 0; } public void run(){ for (int y = -radius; y <= radius; ++y) for (int x = -radius; x <= radius; ++x) shoot(new Point(x,y)); } public void shoot (final Point p){ if (p.x * p.x + p.y * p.y <= radiusQuadrat) ++treffer; } public double value(){ return (double) (treffer) / (double) (radiusQuadrat); } }
public final class Point { public final int x; public final int y; public Point(final int xx, final int yy){ x = xx; y = yy; } }
Werde auch gleich Performancetests durchführen...
EDIT: Habe Point nochmals optimiert.
Liebe Grüße
Steffo
-
Steffo schrieb:
Werde auch gleich Performancetests durchführen...
Ich vermute, Du wirst über die Java-Performance entsetzt sein.
-
Wird interessant, ob der Java Compiler shoot inlined und merkt, dass er kein Point erstellen muss.
-
HereIGo schrieb:
Wird interessant, ob der Java Compiler shoot inlined und merkt, dass er kein Point erstellen muss.
Ich denke nicht, dass er das macht. Ich habe in Java immer die Erfahrung gemacht, dass man kurzlebige Objekte eher vermeiden sollte. Bei C++ ist das hingegen nicht wichtig.
-
Also ich habe das mal mit Java 6 kompiliert (hat jemand Java 7 installiert?!) und mit gcc -03 getestet:
[steffo@localhost performance]$ time ./pi-cpp 3.14159 real 0m2.598s user 0m2.595s sys 0m0.004s [steffo@localhost performance]$ time java Main 3.14159053 real 0m4.468s user 0m4.075s sys 0m0.474s
Hier kommt die C++ Version ohne gcc-Optimierung (konnte ich mir nicht verkneifen :D):
[steffo@localhost performance]$ time ./pi-cpp 3.14159 real 0m32.149s user 0m32.122s sys 0m0.009s
Liebe Grüße
Steffo
-
Michael E. schrieb:
Steffo schrieb:
Michael E. schrieb:
Auch Javaprogramme, die nicht Swing benutzen, werden als langsam empfunden.
Z. B.?
Man sollte den Spieß umdrehen und nach schnellen Javaprogrammen fragen
http://www.heli-x.net/ Die Version 0.9 gibts kostenlos. http://www.heli-x.net/download.shtml
Fühlt sich eigentlich nie wie Java an.
-
Steffo schrieb:
Also ich habe das mal mit Java 6 kompiliert (hat jemand Java 7 installiert?!) und mit gcc -03 getestet:
[steffo@localhost performance]$ time ./pi-cpp 3.14159 real 0m2.598s user 0m2.595s sys 0m0.004s [steffo@localhost performance]$ time java Main 3.14159053 real 0m4.468s user 0m4.075s sys 0m0.474s
[/code]
Oh, interessant. Ich hätte gedacht, dass Java da wesentlich schlechter abschneidet. Kannst Du das auch nochmal mit Werten überpüfen, die eine Größenordnung größer sind. Benchmarks, die 2-3 Sekunden dauern, zeigen in Java zu einem großen Anteil das Laden der JVM.
Außerdem kommt hier die nächste Herausforderung. Da wird Java ein echtes Problem bekommen:
Sortiere ein Array mit 300.000 Point-Objekten nach ihrem Abstand vom Ursprung.
Java wird da aus folgendem Grund ein Problem bekommen: Es gibt in Java einen Overhead für jedes Objekt, der 8 Byte groß ist. Zudem steckst Du nicht die Objekte in das Array, sondern nur Zeiger auf diese Objekte. Auch nochmal 8 Byte. Deshalb sind Java-Objekte einfach viel größer als C++ Objekte. Du sprengst den Cache damit früher, brauchst mehr Speicher und so weiter.
-
HereIGo schrieb:
Wird interessant, ob der Java Compiler shoot inlined und merkt, dass er kein Point erstellen muss.
Anscheinend ist das der Fall!
War es nicht so, daß Java eine Exception schmeißen muß, wenn es integer-Überläufe gibt? Die würden vielleicht das Bißchen mehr an Laufzeit erklären. Kann mir kaum vorstellen, daß new nebst Garbage-Collection so billig ist. Ok, new ist sehr billig, klar. Oder war genug Speicer da, daß kein gc-Lauf überhaupt nötig war?Naja, prinzipiell ist es möglich, einen Optimierer zu schreiben, der erkennt, daß gar kein Point erstellt werden muß. Und prinzipiell ist es möglich, einen Optimierer zu schreiben, der erkennt, daß da noch keine Überläufe entstehen können. Wir messen hier nicht Sprachen aus, sondern nur derzeitige Implementierungen.
Ich hatte vermutet, Jave würde abkacken. Das ist nicht der Fall. 100% mehr ist nichts. Diese langsamen gefühlten Java-Oberflächen haben weit mehr als 1000%. Also daran lag es wohl nicht. Aber am Code liegt es auch nicht, mag ich meinen. Was ich da so gelesen habe, war einfach, zielstrebig, offensichtlich richtig, elegant und bescheiden, offensichtlich schnell. Ich würde mir wünschen, C++-Programmierer würden so gut coden. Warum Java-Anwendungen so unglaublich oft endlos lahm sind, mir ist es ein Rätsel.
ps: Bitte immer mit -march=native testen. Der Java-Jitter darf ja auch den Prozesssor kennen.
-
Steffo: Kannst du mal die final aus dem Point raus machen und schauen, ob das was ändert?
-
Ich habe mal dem Pi-Konstruktor 100000 als Parameter übergeben, wobei sowohl bei der C++- als auch bei der Java-Version Blödsinn rauskommt (es kommt kein PI, sondern eine Zahl kleiner 0 raus):
[steffo@localhost performance]$ time ./pi-cpp -1.003 real 4m19.205s user 4m18.967s sys 0m0.114s [steffo@localhost performance]$ time java Main -1.0029964730543903 real 6m40.989s user 6m41.627s sys 0m1.991s
ps: Bitte immer mit -march=native testen. Der Java-Jitter darf ja auch den Prozesssor kennen.
Das mache ich extra nicht. Weshalb? Zeig mir mal Software, die auf diese Weise kompiliert wird. Das wird man in der Praxis kaum finden. Die Software, die auf deinem Computer läuft wurde garantiert nicht so kompiliert, es sei denn du benutzt Gentoo. Die Stärke von Java ist ja gerade, dass es zur Laufzeit optimieren kann.
Steffo: Kannst du mal die final aus dem Point raus machen und schauen, ob das was ändert?
Kommt gleich.
L. G.
Steffo
-
HereIGo schrieb:
Steffo: Kannst du mal die final aus dem Point raus machen und schauen, ob das was ändert?
Bei new Pi(10000):
[steffo@localhost performance]$ time java Main 3.14159053 real 0m4.682s user 0m4.292s sys 0m0.523s
Liebe Grüße
Steffo
-
Steffo schrieb:
ps: Bitte immer mit -march=native testen. Der Java-Jitter darf ja auch den Prozesssor kennen.
Das mache ich extra nicht. Weshalb? Zeig mir mal Software, die auf diese Weise kompiliert wird. Das wird man in der Praxis kaum finden. Die Software, die auf deinem Computer läuft wurde garantiert nicht so kompiliert, es sei denn du benutzt Gentoo. Die Stärke von Java ist ja gerade, dass es zur Laufzeit optimieren kann.
Ich kann doch auf der CD 12 verschiedene game.exe Dateien anbieten und vom Installer die passende auf die Platte rotzen. Nu werd mal nicht kindisch. Die exe ist so klein, davon kann man 100 draufrotzen, ohne zu leiden. Daß es unüblich ist, ist, weil es normalerweise nur 1% ausmacht. In so einem konstruierten Test solltest Du fair bleiben. Würde ein großer Unterschied sein, würde man 100 exe ausliefern. Da habe ich keine Bange. Da wir theoretisch damit rechnen müssen, daß -march=native viel bringt, um wissenschaftlich zu bleiben, mußt Du leider auch damit messen.
-
Wie auch immer, hat aber nichts gebracht. Das Ergebnis ist bei einem Radius von 10000 sogar schlechter als meine erste Messung.
[steffo@localhost performance]$ g++ -O3 -march=native pi.cpp -o pi-cpp [steffo@localhost performance]$ time ./pi-cpp 3.14159 real 0m2.930s user 0m2.925s sys 0m0.004s
Liebe Grüße
Steffo