Operatoren Was ist schneller: <, <=, ==, >, >=?

H

hüteüberhüte

Gast
Frage steht schon da. Gibt es einen Unterschied zwischen diesen Vergleichsoperatoren? Ist es evtl. sogar typabhängig?
 
B

...ButAlive

Gast
Naja immer < nehmen ist auch eine Stilfrage
Code:
a<3
sieht irgendwie so mädchenhaft aus. Da beißt man dann auch mal in den sauren Apfel und schreibt lieber
Code:
3>a
.

Ernsthaft, der Unterschied, wenn es ihn gibt, ist zu vernachlässigen. Wichtiger ist die Lesbarkeit, in Java hat es sich etabliert links die Variable und rechts die Konstante stehen zu haben. Natürlich kann man es auch umdrehen, aber dann muss man auch beim Lesen immer umdenken.
 
H

hüteüberhüte

Gast
Java:
    public static void main(String[] args) {
        Random r = new Random();
        int i = r.nextInt();
        int j = r.nextInt();
        int k = -1;

        long t1 = System.nanoTime();
        if (i < j) {
            k = 0;
        }
        long t2 = System.nanoTime();
        if (i <= j) {
            k = 1;
        }
        long t3 = System.nanoTime();
        if (i == j) {
            k = 2;
        }
        long t4 = System.nanoTime();
        if (i > j) {
            k = 3;
        }
        long t5 = System.nanoTime();
        if (i >= j) {
            k = 4;
        }
        long t6 = System.nanoTime();

        System.out.println(k);
        System.out.println(t2 - t1 + " ns");
        System.out.println(t3 - t2 + " ns");
        System.out.println(t4 - t3 + " ns");
        System.out.println(t5 - t4 + " ns");
        System.out.println(t6 - t5 + " ns");
    }

Liefert mir:

Code:
1
0 ns
425 ns
0 ns
425 ns
0 ns

Demnach müssten <, == und >= am schnellsten sein. Oder war das jetzt nur Zufall? Oder habe ich ich irgendwas falsch gemacht?
 

Cola_Colin

Top Contributor
4
0 ns
0 ns
311 ns
0 ns
0 ns

4
0 ns
311 ns
0 ns
0 ns
0 ns


4
0 ns
0 ns
311 ns
0 ns
0 ns


Die Ergebnisse sind "zufällig", die "Arbeit" die bei < und Konsorten passiert ist so extrem winzig, dass die Messung wohl selbst von irgendwelcher Strahlung aus dem All verfälscht werden kann.

Lese die Links, die pro2 gepostet hat ;)
 
H

hüteüberhüte

Gast
Besser wäre wohl:
Java:
  public static void main(String[] args) {
    Random r = new Random();
    int i = r.nextInt();
    int j = r.nextInt();

    long t1 = System.nanoTime();
    boolean b1 = i < j;
    long t2 = System.nanoTime();
    boolean b2 = i <= j;
    long t3 = System.nanoTime();
    boolean b3 = i == j;
    long t4 = System.nanoTime();
    boolean b4 = i > j;
    long t5 = System.nanoTime();
    boolean b5 = i >= j;
    long t6 = System.nanoTime();

    System.out.println(b1);
    System.out.println(b2);
    System.out.println(b3);
    System.out.println(b4);
    System.out.println(b5);
    System.out.println(t2 - t1 + " ns");
    System.out.println(t3 - t2 + " ns");
    System.out.println(t4 - t3 + " ns");
    System.out.println(t5 - t4 + " ns");
    System.out.println(t6 - t5 + " ns");
  }

Code:
true
true
false
false
false
0 ns
424 ns
0 ns
425 ns
0 ns

true
true
false
false
false
0 ns
425 ns
0 ns
424 ns
0 ns

false
false
false
true
true
424 ns
425 ns
0 ns
425 ns
0 ns
...

Also irgendwie scheint es doch einen Unterschied zwischen <=, > und <, ==, >= zu geben. Oder das ist einfach nicht messbar.

Zu dem Link:
Usually, the microprocessor does comparison using electrical gates and not step by step like that. It checks all bits at once.

Also wäre es nur logisch, dass es gar keinen Unterschied gibt...
 

Kevin94

Top Contributor
Ohne mir die Messung genau angesehen zu haben, das sagt nichts aber auch rein gar nichts aus, außer das die größtemögliche Genauigkeit einer Zeitmessung in einem Java-Programm auf deinem Rechner etwa 0,5 µs beträgt. Über die Performance sagt es rein garnichts aus. Wiederhol das ein paar Millarden mal, mess davon die Zeiten und dann könnte wir drüber spekulieren ob es da wirklich Unterschiede geben könnte. Aber meine Prophezeiung ist, das du exakt die selben Werte bei so vielen Durchläufen bekommen wirst.

PS: auf meinem Rechner kam folgendes raus, beim ersten Durchlauf:
Code:
4
453 ns
453 ns
0 ns
453 ns
0 ns
 
M

Marcinek

Gast
Bei solchen Betrachtungen müssen weitere Umstände eingerechnet werden. Optimierung der CPU, des Compiler.

Angenommen das würde so stimmen.*)

Und man nutzt immer das teuerste mit 445 Nanosekunden.

Dann könnte ich binnen einer Milisekunde immernoch über 2200 solcher Operationen durchführen.

Die HRT (Human Response Time) liegt bei etwa 100 ms. ;D

Hast du den überhaupt eine Anwendung, bei der es auf solche Zahlen ankommt? Oder worauf möchtest du mit diesem Thread hinaus? - So á la: In 2 Milliarden Jahren verbrennt unsere Sonne ^^



*) Kann aber nicht simmen. Ein vergleich zweier binärcodes ist in einer operation durchzuführen. Ich habe hier 2 Ghz CPUs. Da ich aber soweit unten nicht arbeite, habe ich das kurz bei google überflogen. Nach dem Forenposting da oben ist es in einem Tick durchführbar.
 
H

hüteüberhüte

Gast
Hast du den überhaupt eine Anwendung, bei der es auf solche Zahlen ankommt? Oder worauf möchtest du mit diesem Thread hinaus? - So á la: In 2 Milliarden Jahren verbrennt unsere Sonne ^^

Man kann ja oft schreiben:
Code:
i < 5
oder
Code:
i <= 4
oder
Code:
i != 5
, ohne einen semantischen Unterschied zu erhalten. Meistens wird ersteres bevorzugt. Die Frage ist mir vorhin bei einem Bier in den Sinn gekommen :D
 
H

hüteüberhüte

Gast
Nein, aber ich bin jetzt von so etwas wie
Code:
for (int i = 0; i < 5; i++)
ausgegangen. Streng genommen haben alle drei Ausdrücke natürlich eine unterschiedliche Semantik
 

Marco13

Top Contributor
Diese Zeitmessungen... Hm... ich bin mir nicht sicher, ob das noch ein Auswalzen des Sarkasmus aus der ersten Antwort ist, aber ... man muss damit rechnen, dass nicht: Diese Messungen sind gröbster Unfug. Man könnte viel spekulieren (btw. diese ~400ns sind eben die Timerauflösung auf Windows - auf Linux wären diese Werte AFAIK <100, aber aussagen würden sie trotzdem nichts...)

Wie auch immer:
Java:
class Inequalities
{
     public static void main(String args[])
     {
         int x = 1;
         int y = 2;

         boolean b0 = x < y;
         boolean b1 = x <= y;
         boolean b2 = x ==y;
         boolean b3 = x >= y;
         boolean b4 = x > y;

     }

}


javap -c Inequalities:

Code:
public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iconst_2
   3:   istore_2
   4:   iload_1
   5:   iload_2
   6:   if_icmpge       13
   9:   iconst_1
   10:  goto    14
   13:  iconst_0
   14:  istore_3
   15:  iload_1
   16:  iload_2
   17:  if_icmpgt       24
   20:  iconst_1
   21:  goto    25
   24:  iconst_0
   25:  istore  4
   27:  iload_1
   28:  iload_2
   29:  if_icmpne       36
   32:  iconst_1
   33:  goto    37
   36:  iconst_0
   37:  istore  5
   39:  iload_1
   40:  iload_2
   41:  if_icmplt       48
   44:  iconst_1
   45:  goto    49
   48:  iconst_0
   49:  istore  6
   51:  iload_1
   52:  iload_2
   53:  if_icmple       60
   56:  iconst_1
   57:  goto    61
   60:  iconst_0
   61:  istore  7
   63:  return

}

Wie man sieht werden die alle 1:1 zu bytecode-Instruktionen übersetzt. (Inwieweit das bei if-Abfragen nochmal anders ist, könnte man sich ansehen). Man könnte sich jetzt noch den instruction set von Intel-Prozessoren lesen, und dann philosophieren, wie z.B. das if_cmplt der Stack-Basierten JVM in ein CMP/JCXZ umgewurstet wird, aber selbst dann kommen noch Sachen wie Sprungvorhersage, Optimistic Execution und Cache-Effekte dazu.

Worum geht es eigentlich?
 
H

hüteüberhüte

Gast
Diese Zeitmessungen... Hm... ich bin mir nicht sicher, ob das noch ein Auswalzen des Sarkasmus aus der ersten Antwort ist, aber ... man muss damit rechnen, dass nicht: Diese Messungen sind gröbster Unfug. Man könnte viel spekulieren (btw. diese ~400ns sind eben die Timerauflösung auf Windows - auf Linux wären diese Werte AFAIK <100, aber aussagen würden sie trotzdem nichts...)

Ok, deine Antwort zusammen mit dem Link von pro2 haben jetzt alles erklärt. Lesbarkeit scheint am wichtigsten zu sein und falls es überhaupt zeitliche Unterschiede gibt, so sind diese so gering, dass sie vernachlässigbar sind
 
S

Spacerat

Gast
Also die JVM lässt sich ja mit 'nem virtuellen Prozessor vergleichen. Bei normalen Prozessoren gibt es (Assembler) sog. Branch-Anweisungen (konditionierte Sprünge), die diesen if_cmpxx sehr ähnlich sind. Wie schnell diese Anweisungen im einzelnen sind ist von der Entfernung des Sprungziels abhängig. Die kleineren Entfernungen im Bereich von -128 bis 127 Bytes sind dabei noch am schnellsten. Aber es ist zumindest egal wie der Sprung konditioniert ist - also BEQ (Branch if equal) oder BNE (Branch if not equal) usw. Selbst wenn aber ein Sprungziel weiter weg ist, so bleibt die dafür benötigte Zeit immer noch weit unterhalb des micro-Bereichs (bei Gigahertz-Rechnern zumindest).
 
Zuletzt bearbeitet von einem Moderator:
M

MicroBenchmark

Gast
@Marco
Ich weis zwar nicht warum du immer und immer wieder darauf rumhackst das die Timer-Auflösung der VM unter Windows zu viel langsamer wäre als unter Unix. Es kommt grundsätzlich auf den Hardware-Echtzeit-Systemtaktgeber und die CPU an wie präziese dieser läuft. Und spätestens auf allen Schichten über dem HAL nehmen sich Windows und Unix nichts mehr. Auch hatte ich mal ein Sample mit System.nanoTime() gepostet was deutlich gezeigt hat das die Auflösung unter Win7 Ulti x64 mit Oracle VM 7u5 auf einem Pentium4 531HT deutlich genauer ist als die von dir immer so schlecht geredeten mehreren Millisekunden. Und selbst wenn der Unix-Kernel diesen Wert öfter vom System abfragt und diesen auch irgendwie schneller in die VM bekommt und man dadurch unter Unix wirklich genauere Messergebnisse bekommen würde ... meinst du wirklich das es einen so gewaltigen Unterschied macht ob ich bei einem nichts-sagenden Mikro-Benchmark 100ns oder 150ns als Wert bekomme ? Aussagekraft hat das immer noch nicht.

@TO
Da die VM intern eh mit 32Bit int's rechnet und die mesiten Befehle der virtuellen CPU direkt auf die physische CPU abgebildet werden, und moderne CPUs eine Breite von 64Bit haben ist auf Grund der Tatsache das ein CPU eben aus elektrischen Schaltungen und nicht aus logischen Bausteinen anzunehmen das sowohl 32Bit als auch 64Bit GANZZAHLEN in einem einzigen Takt ausgewertet werden. Wie es da bei heutigen FPUs aussieht weis ich nicht genau, kann mir aber ähnliches vorstellen.
Von daher macht es weder logisch und elektrisch eine Unterschied welchen der Operatoren man verwendet da die CPU für jeden Operator die gleiche Anzahl an Takten benötigt : Daten vom RAM/Cache ins Register laden , Operator anwenden , Ergebnis in RAM/Cache schreiben. Das dürfte insgesamt vielleicht 2 bis 3 Takte sein. Wenn du dann noch dazu nimmst wie viele FLOPS (FloatingPoint Operations Per Secod) von heutigen CPUs in abhängigkeit ihrer Taktfrequenz bewältigt werden können wirst du feststellen das es selbst über einen längeren Zeitraum (und ich rede hier schon von Jahren) kaum eine merkbare Abweichung geben wird.

Ich finde daher die Frage eher sinnlos gestellt da diese auch mit GooGLe selbst zu beantworten gewesen wäre.
 

AquaBall

Top Contributor
So nebenbei:
Abgesehen von der Sinnfreiheit, 1 einzelnen Befehl messen zu wollen.
So ein Code ist ja auch aus anderen Gründen völlig ungeeignet als Benchmark.
Java:
long t1 = System.nanoTime();
  if (i < j) {
    k = 0;
  }
  long t2 = System.nanoTime();
  if (i <= j) {
    k = 1;
  }
...
Wenn eine Bedingung erfüllt wird, dann wird zusätzlicher Code ausgeführt, wenn nicht, dann wird weniger getan.
Somit wird also nicht gleiches miteinander verglichen.
Da braucht man sich über unterschiedliche Ergebnisse nicht wundern. (Zumal die ZufallsZahlen nicht mal bekannt sind.)

Aber letzlich ist es ohnehin vergebliche Müh.
Jede VM und jeder Prozessor haben heute durch die Bank eigenen Befehle für
  • jumpOnEqual
  • jumpOnNotEqual
  • jumpOnLessThen
  • jumpOnLessEqual
  • jumpOnGreaterThen
  • jumpOnGreaterEqual
Somit wird für den Vergleich (bzw. dem sich daraus ergebenden Verzweigungssprung) immer genau 1 Befehl verwendet.
Völlig egal auf welcher Ebene, und auf welchem System.
 

Marco13

Top Contributor
@Marco
Ich weis zwar nicht warum du immer und immer wieder darauf rumhackst das die Timer-Auflösung der VM unter Windows zu viel langsamer wäre als unter Unix. Es kommt grundsätzlich auf den Hardware-Echtzeit-Systemtaktgeber und die CPU an wie präziese dieser läuft. Und spätestens auf allen Schichten über dem HAL nehmen sich Windows und Unix nichts mehr. Auch hatte ich mal ein Sample mit System.nanoTime() gepostet was deutlich gezeigt hat das die Auflösung unter Win7 Ulti x64 mit Oracle VM 7u5 auf einem Pentium4 531HT deutlich genauer ist als die von dir immer so schlecht geredeten mehreren Millisekunden. Und selbst wenn der Unix-Kernel diesen Wert öfter vom System abfragt und diesen auch irgendwie schneller in die VM bekommt und man dadurch unter Unix wirklich genauere Messergebnisse bekommen würde ... meinst du wirklich das es einen so gewaltigen Unterschied macht ob ich bei einem nichts-sagenden Mikro-Benchmark 100ns oder 150ns als Wert bekomme ? Aussagekraft hat das immer noch nicht.

Genau das letztere hatte ich ja auch gesagt. Ich finde zwar nicht, dass ich auf irgendwas "rumhacke", aber dass Windows, abhängig von der Version, unterschiedliche Timerauflösungen hat, die insbesondere nicht "eine Nanosekunde" sind, sollte man sich bewußt machen, wenn man irgendwelche Timing-Tests schreibt. Im Web gibt es genügend Resourcen dazu. Bei manchen kann man davon ausgehen, dass sie sehr profund sind, und von Leuten stammen, die genau wissen, was sie tun und was man beachten muss. Andere stammen aus irgendwelchen Foren, wo anonyme Gäste sowas posten wie "Ich hab' mal was gemessen, und rausgefunden, dass alle anderen etwas falsch gemacht haben", .... ja, who cares. Ich werde auf die Tatsache, dass die Timer-Auflösung nicht "1 Millisekunde" oder gar "1 Nanosekunde" ist, und sie auf Windows (bei den meisten Versionen) im Bereich von mehreren Millisekunden liegt, so lange hinweisen, wie Leute versuchen, die Ausführungzeit einer einzelnen if-Abfrage durch zwei einschließende Aufrufe zu currentTimeMillis oder nanoTime zu messen. Vermutlich also für immer ;)
 
M

maki

Gast
bygones hat also getrollt? Und jeder hat ihm gedankt! =)
Nicht jede Darstellung von Humor ist trollen ;)

IMHO/IME hat diese Frage gar keine Existenzberechtigung in diesem Kontext bzw. ergibt keinen Sinn, der Microbenchmark macht seinem Namen alle Ehre und macht alles ausser sinnvolle Ergebnisse zu liefern.

Aber wegen bygones und ...ButAlives Beiträgen finde ich den Thread trotzdem lesenswert :)
 
H

hüteüberhüte

Gast
So nebenbei:
Abgesehen von der Sinnfreiheit, 1 einzelnen Befehl messen zu wollen.
So ein Code ist ja auch aus anderen Gründen völlig ungeeignet als Benchmark.

Wenn eine Bedingung erfüllt wird, dann wird zusätzlicher Code ausgeführt, wenn nicht, dann wird weniger getan.

Habe mich doch schon korrigiert, siehe http://www.java-forum.org/java-basics-anfaenger-themen/139531-schneller.html#post924009

Weiß auch nicht mehr genau, was ich da gestern alles zusammengeschustert habe

Aber wenn du schnell beantworten könntest, wie man Microbenchmarks sinnvoll durchführt, wäre ich dankbar :) (Ja, wahrscheinlich ist GooGLe an dieser Stelle besser)

@bygones: War das wirklich nur Ironie/Sarkasmus, oder nimmst du vorzugsweise wirklich immer
Code:
<
?
 
H

hüteüberhüte

Gast
Java:
        int i = -1;
        int j = 0;
        int c = 0;

        long t1 = System.nanoTime();
        for (int k = 0; k < 10000; k++) {
            if (i < j) {
                c++;
            } else {
                c++;
            }
        }
        long t2 = System.nanoTime();
        for (int k = 0; k < 10000; k++) {
            if (i <= j) {
                c++;
            } else {
                c++;
            }
        }
        long t3 = System.nanoTime();
        for (int k = 0; k < 10000; k++) {
            if (i == j) {
                c++;
            } else {
                c++;
            }
        }
        long t4 = System.nanoTime();
        for (int k = 0; k < 10000; k++) {
            if (i > j) {
                c++;
            } else {
                c++;
            }
        }
        long t5 = System.nanoTime();
        for (int k = 0; k < 10000; k++) {
            if (i >= j) {
                c++;
            } else {
                c++;
            }
        }
        long t6 = System.nanoTime();

        System.out.println(c);
        System.out.println(t2 - t1 + " ns");
        System.out.println(t3 - t2 + " ns");
        System.out.println(t4 - t3 + " ns");
        System.out.println(t5 - t4 + " ns");
        System.out.println(t6 - t5 + " ns");
Ergibt:
Code:
50000
351232 ns
332120 ns
435748 ns
439995 ns
444243 ns

Java:
        int i = 0;
        int j = -1;
Ergibt:
Code:
50000
440844 ns
425981 ns
431926 ns
352930 ns
344437 ns

Demnach ist
Code:
==
am langsamsten.
Code:
-1 < 0
und
Code:
-1 <= 0
ist schneller als
Code:
-1 > 0
und
Code:
-1 >= 0
.
Code:
0 < -1
und
Code:
0 <= -1
ist langsamer als
Code:
0 > -1
und
Code:
0 >= -1

War das jetzt nur Zufall oder sollte man
Code:
==
vermeiden und besser das verwenden, was häufiger zutrifft? :bahnhof:
 

Noctarius

Top Contributor
Du solltest daran denken, dass der HotSpot Bytecode in nativen Code umkompilieren kann. Daher nutzt man "Warmup-Rounds" damit der HotSpot die Chance hat den Codeflow zu analysieren. Danach gibt man ihm Zeit zu kompilieren, z.B. 3-5s, erst dann startet man die echte Zeitmessung.

Dann sollte man bedenken, dass bei statischen Werten der HotSpot (und auch der Compiler) ganze Codeblöcke austauschen darf, z.B. [c]if (1 < 2) { print("foo"); }[/c] durch [c]print("foo");[/c], damit wären deine Messung hinfällig. Daher niemals statische Werte nutzen für Tests, du kannst niemals sicher sein, dass diese nicht "wegoptimiert" werden.

Microbenchmarking ist eine Kunst, gerade in der JVM wo es extrem viele Sonderfälle zu bedenken gibt, nichts was man mal eben nebenbei macht.
 
S

Spacerat

Gast
Du solltest daran denken, dass der HotSpot Bytecode in nativen Code umkompilieren kann.
Nicht nur kann, sondern auch tut. Soweit ich weis "interpretiert" HotSpot den ByteCode ein mal vor der ersten Ausführung um ihn umzukompilieren und anschliessend nur noch um das erste Kompilat zu optimieren. Wär schön, wenn alle Prozessoren so arbeiten würden, wie dieser virtuelle.
 

Noctarius

Top Contributor
Nein der HotSpot macht während der Laufzeit dauerhafte Codeflow Analyse und kann auch bei plötzlichen Wechseln im If-Statement den nicht nativ kompilierten Branch kurz interpretieren und danach in den anderen 99,9% der Fälle den kompilierten Code nutzen.

Zusätzlich betreiben sowohl Compiler als auch (vor allem) der HotSpot massives Inlining, also komplette Methoden in eine andere Einbauen um den Methodcall und damit den Stackaufbau zu eliminieren.
Dieses Spielchen wurde besonders lustig bei der Einführung des neuen "INVOKEDYNAMIC" Bytecodes. Hier darf sogar die (vom Programm propagierte) Callsite gecached werden.

Auch darf der HotSpot zur Laufzeit eine Escapeanalyse für ValueTypes durchführen und diese durch die reinen Datenwerte auf dem Stack ersetzen um die Objektinstanziierung auf dem Heap zu umgehen.

Und noch vieles mehr ;-)

Eine Ahead-Of-Time Kompilierung gibt es in dieser Art nur für spezielle JVM Klassen (bzw spezielle Klassen aus der Standardlib). .NET nutzt, im Gegensatz zum HotSpot, eine reine (zu mindestens war es mal so) Ahead-Of-Time Kompilierung.

@TO:
Du siehst, der HotSpot und damit die JVM hat soviele Möglichkeiten den Bytecode zu optimieren, dass dein Test nahezu unberechenbar ist ohne JVM Interna ;-)
 
Zuletzt bearbeitet:
S

Spacerat

Gast
Sehr schön detalierte Ausführungen. Die CodeFlow-Analyse während der Ausführung war mir bekannt, sonst könnte HotSpot ja kaum optimieren. Aber wir sind uns doch einig, dass eine JVM zu keiner Zeit auch nur eine Zeile Bytecode ausführt. Klasse wird geladen, native übersetzt und während ein Javaprozess den nativen Code ausführt, optimiert ein weiterer diese 0,1%-Gefahr weg, dass der ausführende Prozess blos keinen ByteCode zu Gesicht bekommt, indem er gerade unbenutzte, native Codepassagen durch optimierte ersetzt. Wenn dem noch nicht so ist, dann wird's Zeit.
[EDIT]Ach ja... evtl. erwartet der TO ja noch 'ne konkrete, simple, sarkasmus- und ironiefreie Antwort: Alle Operatoren sind "gleichschnell".[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
M

maki

Gast
Mit der "Server VM" wird aggressiv vom Hotspot/JIT optimiert, mit der "Client VM" so gut wie gar nicht (aber was heisst das schon genau?;))
Die Server VM gibt es unter Linux per default mit dem JDK, unter Windows gibt es sie nur mit JDK um dem Parameter [c]-server[/c], ein [c]java -version[/c], [c]java -server -version[/c] und [c]java -client -version[/c] zeigen einem welche VM Variante benutzt wird.

@hüteüberhüte
Ich finde die Frage welches schneller ist "falsch", denn diese Frage stellt sich schlciht gar nicht, das kannst du vollkommen ignorieren, ist nur voreilige Optimierung und macht den Code meist hässlicher und die Performance oft schlechter.

Eine "richtige" bzw. bessere Frage wäre:
"Ich habe mit dem Profiler festgestellt, dass diese Codestelle ein Flaschen hals ist, was könnte man probieren?"
Ohne Messung (Profiler) gibt es keine Optimierung!
Davor und danach messen, man wundert sich oft wie theoretische Verbesserungen reale Verschlechterungen zum Ergebnis haben...

Daher schliesse ich mit Spacerats Äusserung an und sage auch "gleich schnell", weil es egal ist solange es kein Problem ist (80/20 Regel).

Ansonsten:
Wir hatten früher im Unterricht einen Mikroprozessor zum programmieren, k.A. mehr welcher das war, da liefen >= und <= schneller als ==, < und >, weil sie direkt per Hardware auf der ALU implementiert waren und alle anderen Vergleichsoperationen mussten mit diesen beiden abgebildet werden.

Nachtrag:
Der Befehlssatz sagt übrigens nicht aus welche Operation direkt per HW implementiert ist.
 
Zuletzt bearbeitet von einem Moderator:

pro2

Bekanntes Mitglied
Mit der "Server VM" wird aggressiv vom Hotspot/JIT optimiert, mit der "Client VM" so gut wie gar nicht (aber was heisst das schon genau?;))
Die Server VM gibt es unter Linux per default mit dem JDK, unter Windows gibt es sie nur mit JDK um dem Parameter [c]-server[/c], ein [c]java -version[/c], [c]java -server -version[/c] und [c]java -client -version[/c] zeigen einem welche VM Variante benutzt wird.

Hm, und wovon darf ich dann ausgehen, wenn ich mit allen drei Fällen exakt das gleiche angezeigt bekomme?

java version "1.7.0_05"
Java(TM) SE Runtime Environment (build 1.7.0_05-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)

Liefe meine Anwendung dann mit dem
Code:
-server
arg genauso, wie ohne?
 

Tobse

Top Contributor
Also ich weiss ja nich, ob das hier nich total hinfällig is, wenn ich das schreibe :D
Java:
nanoStart=System.nanoTime();
for (int i=0;i<runs;i++)
{
	f=a<b;
}
nanoDist=System.nanoTime()-nanoStart;
System.out.println("< mit a<b: "+nanoDist+" ns");
In allen möglichen kombinationen mit runs=10000000:

Code:
< mit a<b: 17195691 ns
< mit a==b: 20180847 ns
< mit a>b: 23380137 ns

<= mit a<b: 13561779 ns
<= mit a==b: 13317335 ns
<= mit a>b: 20400847 ns

== mit a<b: 20270803 ns
== mit a==b: 13471824 ns
== mit a>b: 20068891 ns

!= mit a<b: 13466935 ns
!= mit a==b: 20183780 ns
!= mit a>b: 13967069 ns
-----------------------------------
< mit a<b: 17219647 ns
< mit a==b: 20144669 ns
< mit a>b: 20432625 ns

<= mit a<b: 14058002 ns
<= mit a==b: 13589158 ns
<= mit a>b: 20816403 ns

== mit a<b: 20324091 ns
== mit a==b: 14433469 ns
== mit a>b: 20548003 ns

!= mit a<b: 13924046 ns
!= mit a==b: 20130491 ns
!= mit a>b: 13648802 ns
----------------------------------
< mit a<b: 17446002 ns
< mit a==b: 20230713 ns
< mit a>b: 20631114 ns

<= mit a<b: 13563735 ns
<= mit a==b: 13622401 ns
<= mit a>b: 20995824 ns

== mit a<b: 20325070 ns
== mit a==b: 13549069 ns
== mit a>b: 20250269 ns

!= mit a<b: 13442491 ns
!= mit a==b: 20348536 ns
!= mit a>b: 14292668 ns

ich denk das ergebnis spricht für sich.
und isses nich total egal, wierum mans jetzt macht? der aufwand ist soooo minimal.

[EDIT]
Also wenn man das jetzt zusammenfasst und nach den durchschnittswerten geht, ergibt sich:
Code:
<= mit a==b: 13317335 ns 13589158 ns 13622401 ns | 13509631 ns
!= mit a<b:  13466935 ns 13924046 ns 13442491 ns | 13611156 ns
<= mit a<b:  13561779 ns 14058002 ns 13563735 ns | 13727838 ns
== mit a==b: 13471824 ns 14433469 ns 13549069 ns | 13818120 ns
!= mit a>b:  13967069 ns 13648802 ns 14292668 ns | 13969513 ns
== mit a>b:  20068891 ns 20548003 ns 20250269 ns | 14268388 ns
< mit a<b:   17195691 ns 17219647 ns 17446002 ns | 17287113 ns
< mit a==b:  20180847 ns 20144669 ns 20230713 ns | 20185410 ns
!= mit a==b: 20183780 ns 20130491 ns 20348536 ns | 20220936 ns
== mit a<b:  20270803 ns 20324091 ns 20325070 ns | 20306655 ns
<= mit a>b:  20400847 ns 20816403 ns 20995824 ns | 20737691 ns
< mit a>b:   23380137 ns 20432625 ns 20631114 ns | 21381292 ns

<= oder != sind die schnellsten
[/EDIT]
 
Zuletzt bearbeitet:
M

MicroBenchmark

Gast
Genau das letztere hatte ich ja auch gesagt. Ich finde zwar nicht, dass ich auf irgendwas "rumhacke", aber dass Windows, abhängig von der Version, unterschiedliche Timerauflösungen hat, die insbesondere nicht "eine Nanosekunde" sind, sollte man sich bewußt machen, wenn man irgendwelche Timing-Tests schreibt. Im Web gibt es genügend Resourcen dazu. Bei manchen kann man davon ausgehen, dass sie sehr profund sind, und von Leuten stammen, die genau wissen, was sie tun und was man beachten muss. Andere stammen aus irgendwelchen Foren, wo anonyme Gäste sowas posten wie "Ich hab' mal was gemessen, und rausgefunden, dass alle anderen etwas falsch gemacht haben", .... ja, who cares. Ich werde auf die Tatsache, dass die Timer-Auflösung nicht "1 Millisekunde" oder gar "1 Nanosekunde" ist, und sie auf Windows (bei den meisten Versionen) im Bereich von mehreren Millisekunden liegt, so lange hinweisen, wie Leute versuchen, die Ausführungzeit einer einzelnen if-Abfrage durch zwei einschließende Aufrufe zu currentTimeMillis oder nanoTime zu messen. Vermutlich also für immer ;)

Ich wollte auch eigentlich weniger darauf hinaus das es zwischen verschiedenen Windows-Versionen Unterschiede gibt sondern eher darauf wie du Windows mit Linux in genau diesem speziellen Fall vergleichst.

Das natürlich kein System in der Lage ist genau 1ns Auflösung zu leisten (zumindest nicht in naher Zukunft) sollte alleine aus dem Grund klar sein weil jedes moderne OS auch bei mehreren CPU-Kernen die doch deutlich mehr Threads durchschaltet. Und alleine das sichern der Register eines Threads in den Cache oder gar den RAM , das "clearen" sowie das laden der neuen Werte aus RAM / Cache dauert natürlich länger als 1ns. Und wenn nun noch ein paar mehr Threads durchgeschaltet werden bis der Thread wieder dran ist der in einem Loop "System.nanoTime()" callt (unter anderem natürlich auch auf einem anderen Kern) vergeht natürlich Zeit.

Deiner Aussage aber zu folge müsste Windows ja bei "schlechterer Auflösung" dann öfter mal plötzlich den selben Wert returnen, was es aber zumindest auf meinem System eben NICHT tut.

Auch kann man nicht die genauen Zahlenwerte mit ein ander vergleichen, denn nur weil (wenn deine Aussage wirklich 100% stimmen sollte) ein Wert returned wird der weiter in der Vergangenheit liegt als der Wert der von einem anderen OS returned wird heißt das noch lange nicht das auch dementsprechend mehr Zeit vergangen ist. Eher im Gegenteil : auf grund des "älteren" Wertes würde doch dem User sugeriert das weniger Zeit vergangen ist.

Alles in allem ist also deine Aussage in sich nicht wirklich schlüssig, da halt wie gesagt bei schlechtere Auflösung häufiger "ältere" Werte returned werden und somit eigentlich nur vom Zahlenwert her sogar zeigen würden das angeblich weniger Zeit vergangen ist.
Oder wie würdest du mir das erklären das wenn Windows z.B. 5 returned weil der Wert "älter" ist und Unix 6 der "genauer" wäre für den User klar ist das der Wert von Windows so stark verfälscht ist ? Rein von der Zahl würde jeder denken "Windows ist schneller und präzieser". Und genau damit passt deine Aussage "Windows hat eine schlechtere Zeitauflösung" einfach nicht zusammen.


Das Micro-Benchmarks eh ziemlich sinnfrei sind und erst nach mehrere Milliarden durchläufen (und damit auch natürlich durch JIT optimiert) überhaupt eine halbwegs sinnvolle Aussagekraft haben ist so ziemlich klar, darüber muss man sich nicht streiten.
 
B

bygones

Gast
also ja mein Beitrag war sarkastisch, weil ich eben die Frage an sich schon mehr als witzig finde.

wen man sich wirklich Gedanken macht, welcher Operator schneller ist scheint man kein anderes Problem zu haben und sich auf scheinbare Unterschiede von ca 0.008 sekunden zu verlassen um sein Programm "zu optimieren"
 
H

hüteüberhüte

Gast
Java:
        int i = 0;
        int j = 0;
        boolean b = false;

        long t1 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i < j;
        }
        long t2 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i <= j;
        }
        long t3 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i == j;
        }
        long t4 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i > j;
        }
        long t5 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i >= j;
        }
        long t6 = System.nanoTime();

        System.out.println(b);
        System.out.println(t2 - t1 + " ns");
        System.out.println(t3 - t2 + " ns");
        System.out.println(t4 - t3 + " ns");
        System.out.println(t5 - t4 + " ns");
        System.out.println(t6 - t5 + " ns");

Wird z.B. von der JVM/JIT optimiert, was eine Ausgabe zur Folge hat wie:
Code:
true
6235082 ns
425 ns
0 ns
0 ns
0 ns

Dabei habe ich den Wert nur von 10000 auf 100000 geändert.

Wenn man also wirklich genauer testen möchte, müsste man in der Schleife also irgendetwas anderes schreiben, was so ohne Weiteres nicht aufgelöst werden kann...
 
H

hüteüberhüte

Gast
Dein Test ist auch immer noch falsch. Immer noch kein Warmup, immer noch statische Werte, ...

Gib es einfach auf, dieser Test ist so oder so total sinnfrei -.-

Komischerweise wird selbst das optimiert:
Java:
        long t1 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i < j++;
        }
        long t2 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i <= j++;
        }
        long t3 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i == j++;
        }
        long t4 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i > j++;
        }
        long t5 = System.nanoTime();
        for (int k = 0; k < 100000; k++) {
            b = i >= j++;
        }
        long t6 = System.nanoTime();

Also gut, ich geb's erst mal dran. ;)

Danke für die vielen Antworten und die Zeit, die sich mit diesem Thema beschäftigt wurde! :)
 
B

...ButAlive

Gast
Ich bin auch der Meinung, dass der Test rein gar nichts aussagt. Aber selbst wenn da irgendwas dran sein sollte, dass man pro 100 000 Vergleichen rund 0,0007 Sekunden sparen würde, dann bräuchtest ganz schon viele Vergleiche um die Lebenszeit, die du für dieses Erkenntnis gebraucht hast, wieder reinzuholen.

Ausgehend davon dass du dich seit ungefähr 3 Tagen mit dem Thema beschäftigst wäre das folgendes:

Um eine Sekunde zu sparen, brauchst du 1 / 0,0007 * 100 000 ≈ 14 285 714,3 Vergleiche.

Um einen Tag wieder reinzuholen, brauchst du 24 * 60 * 60 * 14 285 714,3 ≈ 1,23 Billionen Vergleiche

Um die ganzen 3 Tage wieder reinzuholen brauchst du also ungefähr 3,7 Billionen Vergleiche.
 
H

hüteüberhüte

Gast
Alles klar, aber langsam wird es doch OT. Kurios wäre es nur, wenn
Code:
!(i < j || i > j)
schneller wäre als
Code:
i == j
:D
 
B

...ButAlive

Gast
Ich wollte eigentlich nicht OT werden, wollte dir nur ein Gefühl dafür geben, über was für Dimensionen wir diskutieren, wenn es um solche Microoptimierungen geht.
 

Noctarius

Top Contributor
Warum sollte dein Test nicht wegoptimiert werden? Variable b hat eine Zuweisung welche nie gebraucht wird. Da die Berechnung ohne Seiteneffekte ist und der Wert von b nicht genutzt wird darf der Compiler die Berechnung sogar ganz wegwerfen.
Wie bereits mehrfach angesprochen: Microbenchmarks sind immer mit Vorsicht zu genießen und ohne echtes Interna Wissen der JVM nahezu nicht gescheit zu entwickeln.
 
S

Spacerat

Gast
Das Thema sieht zwar erledigt aus, aber wenn's unbedingt notwendig ist, einen "sinnvolleren" Microbenchmark hinzuzaubern, dann lagert die zu testenden Befehle doch in Methoden aus:
Java:
boolean beq(int a, int b) {
  return a == b;
}

boolean bne(int a, int b) {
  return a != b;
}

//...
In Assembler funktioniert's (nach wie vor nur ohne Multitasking!) zumindest, aber da gibt's ja auch keinen JIT, der sich um Optimierung kümmert.
 
H

hüteüberhüte

Gast
Warum sollte dein Test nicht wegoptimiert werden? Variable b hat eine Zuweisung welche nie gebraucht wird.

Du hast
Code:
System.out.println(b);
übersehen ;) Es gibt schon mehrere Schreibstellen und eine Lesestelle...

Oder meinst du jetzt, alle Schreibstellen, auf denen keine Lesestelle folgt, werden zusammengefasst? Woher weiß die Laufzeitumgebung dann, welche Schreibstelle die letzte vor einer Lesestelle ist? Hm
 

Noctarius

Top Contributor
Wenn überhaupt bleibt die letzte Zuweisung an b übrig, da aber alle Werte konstant sind könnte es sogar sein, dass der Compiler genau eine Zuweisung übrig lässt.
Grundsätzlich gibt dein Code IMMER das Selbe aus also kann man sich die "Berechnung" sparen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
E schneller von der Datenbank abfragen Java Basics - Anfänger-Themen 15
C Ein Algorithmus soll schneller werden Java Basics - Anfänger-Themen 24
Hallolu Pong-Spiel: Schläger schneller werden lassen Java Basics - Anfänger-Themen 9
S Was ist schneller: direkte Sortierung oder indirekt ueber eine SortedMap..? Java Basics - Anfänger-Themen 10
M Schneller Timer Java Basics - Anfänger-Themen 2
P Schneller Quadratzahltest für beliebig große natürliche Zahlen Java Basics - Anfänger-Themen 2
H Collections Was ist schneller - HashMap + Sort v TreeMap? Java Basics - Anfänger-Themen 75
P schneller Sort ? Java Basics - Anfänger-Themen 2
V Double schneller als Float? Java Basics - Anfänger-Themen 13
R ArrayList sehr viel schneller als Array? Java Basics - Anfänger-Themen 2
Dit_ Was ist schneller | < oder >= Java Basics - Anfänger-Themen 6
M Java URLConnection schneller bekommen Java Basics - Anfänger-Themen 3
M schneller Klassenvergleich Java Basics - Anfänger-Themen 2
A Datein kopieren: File oder xcopy? Was ist schneller? Java Basics - Anfänger-Themen 10
R java-programme schneller laufen lassen Java Basics - Anfänger-Themen 41
M Mehrere Threads nutzen --> run() schneller als start(), Warum? Java Basics - Anfänger-Themen 3
ruerob Warum ist Timer schneller als While? Java Basics - Anfänger-Themen 9
J Wie java programm noch schneller machen? Java Basics - Anfänger-Themen 30
S LinkedList indexOf() - geht des irgendwie schneller? Java Basics - Anfänger-Themen 23
O String-Prüfung: Was ist besser/schneller? Java Basics - Anfänger-Themen 15
S Schneller Zugriff auf Liste mit sortierten Flaechen..? Java Basics - Anfänger-Themen 7
G Arraysuche schneller ausführen? Java Basics - Anfänger-Themen 14
H Serialization: Was ist besser(schneller) Binary <-> XM Java Basics - Anfänger-Themen 2
N Schneller als FileWriter? Java Basics - Anfänger-Themen 28
G Bessere Lösung für SQL STMNT ? (Schneller?) Java Basics - Anfänger-Themen 4
C was is schneller Vector oder double Array Java Basics - Anfänger-Themen 5
G java optimieren. wie daten schneller in mysqlDB schreiben? Java Basics - Anfänger-Themen 15

Ähnliche Java Themen

Neue Themen


Oben