it-swarm.com.de

System.currentTimeMillis vs System.nanoTime

Genauigkeit vs. Präzision

Was ich wissen möchte ist, ob ich System.currentTimeMillis () oder System.nanoTime () verwenden soll, wenn ich die Positionen meines Objekts in meinem Spiel aktualisiere? Ihre Bewegungsänderung ist direkt proportional zur seit dem letzten Anruf verstrichenen Zeit, und ich möchte so präzise wie möglich sein.

Ich habe gelesen, dass es einige ernsthafte Probleme mit der Zeitauflösung zwischen verschiedenen Betriebssystemen gibt (nämlich, dass Mac/Linux eine Auflösung von fast 1 ms hat, während Windows eine Auflösung von 50 ms hat?). Ich verwende meine Apps hauptsächlich unter Windows und die Auflösung von 50 ms scheint ziemlich ungenau zu sein.

Gibt es bessere Optionen als die beiden, die ich aufgelistet habe?

Anregungen/Kommentare?

362
mmcdole

Wenn Sie nur nach extrem präzisen Messungen der verstrichenen Zeit suchen, verwenden Sie System.nanoTime(). System.currentTimeMillis() gibt Ihnen die genaueste Zeit in Millisekunden seit der Epoche an, System.nanoTime() gibt Ihnen jedoch eine nanosekundengenaue Zeit relativ zu einem beliebigen Punkt an.

Aus der Java Dokumentation:

public static long nanoTime()

Gibt den aktuellen Wert des genauesten verfügbaren Systemzeitgebers in Nanosekunden zurück.

Diese Methode kann nur zum Messen der verstrichenen Zeit verwendet werden und steht in keinem Zusammenhang mit einem anderen Begriff der System- oder Wanduhrzeit. Der zurückgegebene Wert repräsentiert Nanosekunden seit einer festgelegten, aber willkürlichen Zeit (möglicherweise in der Zukunft, daher können die Werte negativ sein). Dieses Verfahren liefert eine Nanosekundengenauigkeit, jedoch nicht unbedingt eine Nanosekundengenauigkeit. Es wird keine Garantie dafür übernommen, wie häufig sich die Werte ändern. Unterschiede bei aufeinanderfolgenden Aufrufen, die länger als ungefähr 292 Jahre dauern (263 Nanosekunden) berechnet die verstrichene Zeit aufgrund eines numerischen Überlaufs nicht genau.

Um beispielsweise zu messen, wie lange die Ausführung von Code dauert, gehen Sie wie folgt vor:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

Siehe auch: JavaDoc System.nanoTime () und JavaDoc System.currentTimeMillis () für weitere Informationen.

308
dancavallaro

Da dies sonst niemand erwähnt hat ...

Es ist nicht sicher, die Ergebnisse von System.nanoTime() -Aufrufen zwischen verschiedenen Threads zu vergleichen. Selbst wenn die Ereignisse der Threads in einer vorhersagbaren Reihenfolge auftreten, kann der Unterschied in Nanosekunden positiv oder negativ sein.

System.currentTimeMillis() ist für die Verwendung zwischen Threads sicher.

92
gubby

Update von Arkadiy : Ich habe unter Windows 7 in Oracle ein korrekteres Verhalten von System.currentTimeMillis() beobachtet Java 8. Die Zeit wurde mit 1 Millisekunde zurückgegeben Der Quellcode in OpenJDK hat sich nicht geändert, daher weiß ich nicht, was das bessere Verhalten verursacht.


David Holmes von Sun hat vor ein paar Jahren einen Blog-Artikel gepostet, in dem die Timing-APIs Java) (insbesondere System.currentTimeMillis() und System.nanoTime() sehr ausführlich beschrieben werden. ), wann Sie welche verwenden möchten und wie sie intern arbeiten.

In der Hotspot-VM: Uhren, Zeitgeber und Planungsereignisse - Teil I - Windows

Ein sehr interessanter Aspekt des Timers, der von Java unter Windows für APIs mit einem zeitgesteuerten Warteparameter verwendet wird, besteht darin, dass sich die Auflösung des Timers in Abhängigkeit davon ändern kann, welche anderen API-Aufrufe vorgenommen wurden - System wide (nicht nur in dem bestimmten Prozess) .Er zeigt ein Beispiel, in dem die Verwendung von Thread.sleep() diese Auflösungsänderung verursacht.

58
Michael Burr

System.nanoTime() wird in älteren JVMs nicht unterstützt. Wenn das ein Problem ist, bleiben Sie bei currentTimeMillis

Bezüglich der Genauigkeit liegen Sie fast richtig. Auf einigen Windows-Computern hat currentTimeMillis() eine Auflösung von ca. 10 ms (nicht 50 ms). Ich weiß nicht warum, aber einige Windows-Computer sind genauso genau wie Linux-Computer.

Ich habe GAGETimer in der Vergangenheit mit mäßigem Erfolg verwendet.

10
Paul Morel

Wie bereits erwähnt, ist currentTimeMillis die Uhrzeit, die sich aufgrund der Sommerzeit ändert. Benutzer ändern die Zeiteinstellungen, die Schaltsekunden und die Internetzeitsynchronisierung. Wenn Ihre App von monoton steigenden Werten für die abgelaufene Zeit abhängt, bevorzugen Sie möglicherweise nanoTime.

Du denkst vielleicht, dass die Spieler während des Spiels nicht an den Zeiteinstellungen herumspielen, und vielleicht hast du recht. Unterschätzen Sie jedoch nicht die Unterbrechung durch Internet-Zeitsynchronisierung oder Remotedesktopbenutzer. Die nanoTime API ist immun gegen diese Art von Störungen.

Wenn Sie die Uhrzeit verwenden möchten, aber Unterbrechungen aufgrund der Internetzeitsynchronisierung vermeiden möchten, können Sie einen NTP) - Client wie Meinberg in Betracht ziehen, der die Taktrate auf Null stellt, anstatt stellen Sie einfach die Uhr in regelmäßigen Abständen zurück.

Ich spreche aus eigener Erfahrung. In einer von mir entwickelten Wetteranwendung wurden zufällig auftretende Windgeschwindigkeitsspitzen festgestellt. Es dauerte eine Weile, bis mir klar wurde, dass meine Zeitbasis durch das Verhalten der Uhrzeit auf einem typischen PC gestört wurde. Alle meine Probleme verschwanden, als ich anfing, nanoTime zu verwenden. Konsistenz (Monotonie) war für meine Anwendung wichtiger als rohe Präzision oder absolute Genauigkeit.

9
KarlU

Ja, wenn eine solche Genauigkeit erforderlich ist, verwenden Sie System.nanoTime(), aber beachten Sie, dass Sie dann eine Java 5+ JVM benötigen.

Auf meinen XP) Systemen wird mindestens die Systemzeit gemeldet 100 Mikrosekunden 278 Nanosekunden unter Verwendung des folgenden Codes:

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }
5
Lawrence Dol

Verwenden Sie für Spielgrafiken und flüssige Positionsaktualisierungen System.nanoTime() anstelle von System.currentTimeMillis(). Ich bin in einem Spiel von currentTimeMillis () auf nanoTime () umgestiegen und habe eine deutliche visuelle Verbesserung der Bewegungsfreiheit erzielt.

Während eine Millisekunde so aussehen mag, als ob sie bereits präzise sein sollte, ist dies visuell nicht der Fall. Die Faktoren nanoTime() können Folgendes verbessern:

  • genaue Pixelpositionierung unterhalb der Wanduhrauflösung
  • möglichkeit zum Antialiasing zwischen Pixeln, wenn Sie möchten
  • Ungenauigkeit der Windows-Wanduhr
  • clock Jitter (Inkonsistenz, wann die Wanduhr tatsächlich vorwärts tickt)

Wie andere Antworten vermuten lassen, verursacht nanoTime bei wiederholtem Aufruf Performance-Kosten. Am besten rufen Sie es nur einmal pro Frame auf und verwenden denselben Wert, um den gesamten Frame zu berechnen.

3
Thomas W

Ich habe gute Erfahrungen mit Nanotime gemacht. Mithilfe einer JNI-Bibliothek wird die Wanduhrzeit in zwei Längen (Sekunden seit der Epoche und Nanosekunden innerhalb dieser Sekunde) angegeben. Es ist mit dem vorkompilierten JNI-Teil für Windows und Linux verfügbar.

2
Jon Bright

System.currentTimeMillis() ist für die abgelaufene Zeit nicht sicher, da diese Methode auf die System-Echtzeituhränderungen des Systems anspricht. Sie sollten System.nanoTime Verwenden. Bitte beziehen Sie sich auf Java System-Hilfe:

Über die nanoTime-Methode:

.. Diese Methode liefert eine Nanosekundengenauigkeit, aber nicht unbedingt eine Nanosekundenauflösung (das heißt, wie oft sich der Wert ändert). Es werden keine Garantien abgegeben, außer dass die Auflösung mindestens so gut ist wie die von currentTimeMillis ().

Wenn Sie System.currentTimeMillis() verwenden, kann die abgelaufene Zeit negativ sein (Back <- to the future)

0
Ricardo Gasca