Wie im Blog-Beitrag Vorsicht vor System.nanoTime () in Java dokumentiert , gibt Javas System.nanoTime () auf x86-Systemen den Zeitwert mithilfe eines CPU- spezifischen Zählers zurück. Betrachten Sie nun den folgenden Fall, mit dem ich die Zeit eines Anrufs messe:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
In einem Mehrkernsystem kann es sein, dass der Thread nach dem Messen der Zeit1 für einen anderen Prozessor geplant wird, dessen Zähler kleiner als der der vorherigen CPU ist. Somit könnten wir in time2 einen Wert erhalten, der kleiner als time1 ist. Somit würden wir in timeSpent einen negativen Wert erhalten.
Ist System.nanotime in diesem Fall nicht vorerst so gut wie nutzlos?
Ich weiß, dass das Ändern der Systemzeit keinen Einfluss auf die Nanotime hat. Das ist nicht das Problem, das ich oben beschreibe. Das Problem ist, dass jede CPU einen anderen Zähler behält, seit sie eingeschaltet wurde. Dieser Zähler kann bei der zweiten CPU niedriger sein als bei der ersten CPU. Da der Thread vom Betriebssystem nach dem Abrufen von time1 auf die zweite CPU eingeplant werden kann, ist der Wert von timeSpent möglicherweise falsch und sogar negativ.
Antworten:
Diese Antwort wurde 2011 unter dem Gesichtspunkt geschrieben, was das Sun JDK der damaligen Zeit auf Betriebssystemen tatsächlich tat. Das ist eine lange Zeit her! Die Antwort von leventov bietet eine aktuellere Perspektive.
Dieser Beitrag ist falsch und
nanoTime
sicher. Es gibt einen Kommentar zu dem Beitrag, der auf einen Blog-Beitrag von David Holmes verweist, einem Echtzeit- und Parallelitäts-Typ bei Sun. Es sagt:Also, auf Windows, dies war ein Problem , bis WinXP SP2, aber es ist jetzt nicht.
Ich kann keinen Teil II (oder mehr) finden, der über andere Plattformen spricht, aber dieser Artikel enthält eine Bemerkung, dass Linux auf dieselbe Weise auf dasselbe Problem gestoßen ist und es gelöst hat, mit einem Link zu den FAQ für clock_gettime (CLOCK_REALTIME). , was sagt:
Wenn Holmes 'Link als Hinweis auf diese
nanoTime
Aufrufe gelesen werden kannclock_gettime(CLOCK_REALTIME)
, ist er ab Kernel 2.6.18 auf x86 und immer auf PowerPC sicher (da IBM und Motorola im Gegensatz zu Intel tatsächlich wissen, wie man Mikroprozessoren entwirft).SPARC oder Solaris werden leider nicht erwähnt. Und natürlich haben wir keine Ahnung, was IBM JVMs tun. Aber Sun JVMs unter modernen Windows- und Linux-Versionen machen das richtig.
BEARBEITEN: Diese Antwort basiert auf den zitierten Quellen. Aber ich mache mir immer noch Sorgen, dass es tatsächlich völlig falsch sein könnte. Einige aktuellere Informationen wären wirklich wertvoll. Ich bin gerade auf einen Link zu einem vier Jahre neueren Artikel über Linux-Uhren gestoßen, der nützlich sein könnte.
quelle
void foo() { Thread.sleep(40); }
einer negativen Zeit (-380 ms!) Mit einem einzelnenAthlon 64 X2 4200+
ProzessorIch habe ein bisschen gesucht und festgestellt, dass wenn man pedantisch ist, es ja als nutzlos angesehen werden kann ... in bestimmten Situationen ... es hängt davon ab, wie zeitkritisch Ihre Anforderungen sind ...
Schauen Sie sich dieses Zitat auf der Java Sun-Website an:
Java hat auch eine Einschränkung für die nanoTime () -Methode:
Es scheint, dass die einzige Schlussfolgerung, die gezogen werden kann, darin besteht, dass nanoTime () nicht als genauer Wert herangezogen werden kann. Wenn Sie also keine Zeiten messen müssen, die nur Nanosekunden voneinander entfernt sind, ist diese Methode auch dann gut genug, wenn der resultierende Rückgabewert negativ ist. Wenn Sie jedoch eine höhere Präzision benötigen, empfehlen sie anscheinend die Verwendung von JAVA RTS.
Um Ihre Frage zu beantworten ... no nanoTime () ist nicht nutzlos ... es ist einfach nicht die umsichtigste Methode, die in jeder Situation angewendet werden kann.
quelle
-100
,-99
,-98
(Natürlich viel größere Werte in der Praxis). Sie gehen in die richtige Richtung (zunehmend), daher gibt es hier kein Problem.Keine Notwendigkeit zu debattieren, verwenden Sie einfach die Quelle. Hier, SE 6 für Linux, machen Sie Ihre eigenen Schlussfolgerungen:
quelle
Seit Java 7
System.nanoTime()
ist die Sicherheit durch die JDK-Spezifikation garantiert.System.nanoTime()
Javadoc macht deutlich, dass alle beobachteten Aufrufe innerhalb einer JVM (dh über alle Threads hinweg) monoton sind:Die JVM / JDK-Implementierung ist dafür verantwortlich, die Inkonsistenzen auszubügeln, die beim Aufrufen der zugrunde liegenden Betriebssystem-Dienstprogramme auftreten können (z. B. die in der Antwort von Tom Anderson genannten ).
Die meisten anderen alten Antworten auf diese Frage (geschrieben 2009–2012) drücken FUD aus, das wahrscheinlich für Java 5 oder Java 6 relevant war, aber für moderne Versionen von Java nicht mehr relevant ist.
Es ist jedoch erwähnenswert, dass es trotz der
nanoTime()
Sicherheit von JDK-Garantien mehrere Fehler in OpenJDK gab, die dazu führten, dass diese Garantie auf bestimmten Plattformen oder unter bestimmten Umständen nicht eingehalten wurde (z. B. JDK-8040140 , JDK-8184271 ). Derzeit gibt es keine offenen (bekannten) Fehler in OpenJDKnanoTime()
, aber die Entdeckung eines neuen solchen Fehlers oder eine Regression in einer neueren Version von OpenJDK sollte niemanden schockieren.In diesem Sinne sollte Code, der
nanoTime()
für zeitgesteuertes Blockieren, Warten auf Intervalle, Zeitüberschreitungen usw. verwendet wird, negative Zeitdifferenzen (Zeitüberschreitungen) vorzugsweise als Nullen behandeln, anstatt Ausnahmen auszulösen. Diese Praxis ist auch bevorzugt , weil es mit dem Verhalten aller zeitlichen Warten Methoden in allen Klassen in Einklang stehtjava.util.concurrent.*
, zum BeispielSemaphore.tryAcquire()
,Lock.tryLock()
,BlockingQueue.poll()
etc.Dennoch
nanoTime()
sollte für die Implementierung von zeitgesteuertem Blockieren, Warten auf Intervalle, Zeitüberschreitungen usw. immer noch bevorzugt werden,currentTimeMillis()
da letzteres dem Phänomen "Rücklaufzeit" unterliegt (z. B. aufgrund der Serverzeitkorrektur), dhcurrentTimeMillis()
nicht zum Messen von Zeitintervallen geeignet ist überhaupt. Weitere Informationen finden Sie in dieser Antwort .Anstatt die
nanoTime()
Messungen der Codeausführungszeit direkt zu verwenden, sollten vorzugsweise spezielle Benchmarking-Frameworks und -Profiler verwendet werden, z. B. JMH und Async-Profiler im Wall-Clock-Profiling-Modus .quelle
Haftungsausschluss: Ich bin der Entwickler dieser Bibliothek
Das könnte dir besser gefallen:
http://juliusdavies.ca/nanotime/
Es kopiert jedoch eine DLL- oder Unix .so-Datei (Shared Object) in das Home-Verzeichnis des aktuellen Benutzers, damit es JNI aufrufen kann.
Einige Hintergrundinformationen finden Sie auf meiner Website unter:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
quelle
Linux korrigiert Diskrepanzen zwischen CPUs, Windows jedoch nicht. Ich schlage vor, Sie gehen davon aus, dass System.nanoTime () nur auf etwa 1 Mikrosekunde genau ist. Eine einfache Möglichkeit, ein längeres Timing zu erzielen, besteht darin, foo () 1000 oder mehr Mal aufzurufen und die Zeit durch 1000 zu teilen.
quelle
Absolut nicht nutzlos. Timing-Liebhaber weisen korrekt auf das Multi-Core-Problem hin, aber in Real-Word-Anwendungen ist es oft radikal besser als currentTimeMillis ().
Bei der Berechnung von Grafikpositionen in Bildaktualisierungen führt nanoTime () zu VIEL sanfteren Bewegungen in meinem Programm.
Und ich teste nur auf Mehrkernmaschinen.
quelle
Bei der Verwendung von System.nanoTime () wurde eine negative verstrichene Zeit gemeldet. Um klar zu sein, lautet der fragliche Code:
und die Variable 'elapsedNanos' hatte einen negativen Wert. (Ich bin mir sicher, dass der Zwischenaufruf auch weniger als 293 Jahre gedauert hat, was der Überlaufpunkt für Nanos ist, die in Longs gespeichert sind :)
Dies geschah mit einer IBM v1.5 JRE 64-Bit auf IBM P690-Hardware (Multi-Core) unter AIX. Ich habe diesen Fehler nur einmal gesehen, daher scheint er äußerst selten zu sein. Ich kenne die Ursache nicht - ist es ein hardwarespezifisches Problem, ein JVM-Defekt - ich weiß es nicht. Ich kenne auch die Auswirkungen auf die Genauigkeit von nanoTime () im Allgemeinen nicht.
Um die ursprüngliche Frage zu beantworten, halte ich nanoTime nicht für nutzlos - es bietet ein Timing unter einer Millisekunde, aber es besteht ein tatsächliches (nicht nur theoretisches) Risiko, dass es ungenau ist, das Sie berücksichtigen müssen.
quelle
Dies scheint auf einem Core 2 Duo unter Windows XP und JRE 1.5.0_06 kein Problem zu sein.
In einem Test mit drei Threads sehe ich nicht, dass System.nanoTime () rückwärts geht. Die Prozessoren sind beide beschäftigt, und Threads gehen gelegentlich in den Ruhezustand, um sich bewegende Threads zu provozieren.
[EDIT] Ich würde vermuten, dass dies nur auf physisch getrennten Prozessoren geschieht, dh dass die Zähler für mehrere Kerne auf demselben Chip synchronisiert sind.
quelle
Nein, es ist nicht ... Es hängt nur von Ihrer CPU ab. Überprüfen Sie den High Precision Event Timer, wie / warum die Dinge je nach CPU unterschiedlich behandelt werden.
Lesen Sie im Grunde die Quelle Ihres Java und überprüfen Sie, was Ihre Version mit der Funktion macht. Wenn sie gegen die CPU funktioniert, werden Sie sie ausführen.
IBM schlägt sogar vor, dass Sie es für das Leistungsbenchmarking verwenden (ein Beitrag von 2008, aber aktualisiert).
quelle
Ich verweise auf die im Wesentlichen gleiche Diskussion, in der Peter Lawrey eine gute Antwort gibt. Warum erhalte ich mit System.nanoTime () eine negative verstrichene Zeit?
Viele Leute erwähnten, dass in Java System.nanoTime () eine negative Zeit zurückgegeben werden könnte. Ich entschuldige mich dafür, dass ich wiederholt habe, was andere Leute bereits gesagt haben.
Es wäre cool, wenn System.nanoTime () die CoreID zurückgeben würde, in der sie ausgeführt wurde.
quelle
Java ist plattformübergreifend und nanoTime ist plattformabhängig. Wenn Sie Java verwenden - wenn Sie nanoTime nicht verwenden. Ich habe mit dieser Funktion echte Fehler in verschiedenen JVM-Implementierungen gefunden.
quelle
In der Java 5-Dokumentation wird auch empfohlen, diese Methode für denselben Zweck zu verwenden.
Java 5 API Doc
quelle
Ändert sich auch,
System.currentTimeMillies()
wenn Sie die Uhr Ihres Systems ändern, währendSystem.nanoTime()
dies nicht der Fall ist. Letzteres ist daher sicherer, um die Dauer zu messen.quelle
nanoTime
ist für das Timing extrem unsicher. Ich habe es mit meinen grundlegenden Primalitätstestalgorithmen ausprobiert und es gab Antworten, die für dieselbe Eingabe buchstäblich eine Sekunde voneinander entfernt waren. Verwenden Sie diese lächerliche Methode nicht. Ich brauche etwas, das genauer und präziser ist als Zeit Millis, aber nicht so schlimm wienanoTime
.quelle