Bester Ansatz für den Umgang mit Zeitmaßnahmen? [Duplikat]

8

Mein Ziel ist es, ein Framework für die Messung der Methodenausführung oder Transaktionszeit und für die Verarbeitung der Messungen zu schreiben, d. h. Speicherung, Analyse usw. Die Transaktion kann Aufrufe an externe Systeme umfassen, die synchron oder asynchron auf die Ergebnisse warten.

Es gab bereits einige Fragen zu diesem Thema, wie

Und alle Antworten laufen auf drei Ansätze hinaus, um sich die Zeit zu nehmen

  • System.currentTimeMillis()
  • System.nanoTime()
  • Instant.now() und Duration (seit Java 8)

Ich weiß, all diese Dinge haben einige Auswirkungen

System.currentTimeMillis ()

Das Ergebnis dieser Methode hängt von der Plattform ab. Unter Linux erhalten Sie 1ms Auflösung, von Windows erhalten Sie 10ms (Single Core) ~ 15ms (Multi Core). Es ist also in Ordnung, große laufende Operationen oder mehrere Ausführungen von kurz laufenden Operationen zu messen.

System.nanoTime ()

Sie erhalten ein hochauflösendes Zeitmaß mit einer Genauigkeit von Nanosekunden (aber nicht unbedingt mit einer Genauigkeit von Nanosekunden) und Sie erhalten nach 292 Jahren einen Überlauf (damit könnte ich leben).

Instant.now () und Dauer

Seit Java 8 gibt es die neue Zeit-API. Ein Instant hat ein zweites und ein zweites Nanosekundenfeld, so dass es oberhalb der Objektreferenz zwei lange Werte verwendet (dasselbe für Duration ). Abhängig von der zugrunde liegenden Uhr erhalten Sie auch eine zweite Nanosekunde (siehe "Java 8 Instant.") .now () mit Nanosekundenauflösung? "). Die Instantiierung erfolgt durch Aufruf von Instant.now() , das für die normale Systemuhr auf System.currentTimeMillis() abgebildet wird.

Angesichts der Fakten wird klar, dass die beste Genauigkeit nur mit System.nanoTime() erreicht werden kann, aber meine Frage zielt eher auf eine Best-Practice für den Umgang mit den Maßnahmen im Allgemeinen ab, die nicht nur beinhaltet die Maßnahme, aber auch die Handhabung der Maßnahme.

  • Instant und Duration bieten die beste API-Unterstützung (Berechnung, Vergleich, usw.), haben aber os-abhängige Genauigkeit im Standardfall und mehr Overhead für Speicher und Erstellen einer Kennzahl (Objekterstellung, tieferes Callstack)

  • System.nanoTime () und System.currentTimeMillis () haben unterschiedliche Genauigkeitsgrade, aber nur grundlegende "api" -Unterstützung (mathematische Operationen auf long), sind aber schneller zu erhalten und kleiner im Speicher zu halten.

Was wäre der beste Ansatz? Gibt es irgendwelche Implikationen, an die ich nicht gedacht habe? Gibt es Alternativen?

    
Gerald Mücke 06.05.2016, 08:40
quelle

2 Antworten

4

Sie konzentrieren sich zu sehr auf das unwichtige Detail der Präzision. Wenn Sie die Ausführung bestimmter Operationen messen / profilieren möchten, müssen Sie sicherstellen, dass diese Vorgänge so lange ausgeführt werden, dass die Messung von einmaligen Artefakten, kleinen Unterschieden im Timing der Thread-Planung, Garbage Collection oder HotSpot-Optimierung unbeeinflusst bleibt. In den meisten Fällen, wenn die Unterschiede kleiner als die Millisekundenskala werden, sind sie nicht sinnvoll, um daraus Schlüsse zu ziehen.

Der wichtigere Aspekt ist, ob die Tools für Ihre Aufgabe konzipiert sind. System.currentTimeMillis() und alle anderen wall-clock-basierten APIs, unabhängig davon, ob sie auf currentTimeMillis() oder nicht basieren, sind so konzipiert, dass sie eine Uhr liefern, die mit der Erdrotation und ihrem Umlauf um die Sonne synchronisiert werden soll die Last von Leap Seconds und anderen Korrekturmaßnahmen, ganz zu schweigen von der Tatsache, dass die Uhr Ihres Computers möglicherweise nicht synchron ist die Wanduhr sowieso und korrigiert werden, z via NTP-Updates, im schlimmsten Fall springen Sie rechts, wenn Sie versuchen, Ihre verstrichene Zeit zu messen, vielleicht sogar rückwärts.

Im Gegensatz dazu ist System.nanoTime() entworfen, um abgelaufene Zeit zu messen (genau das, was Sie tun wollen) und sonst nichts. Da sein Rückgabewert einen unbestimmten Ursprung hat und sogar negativ sein kann, machen nur Unterschiede zwischen zwei Werten, die von dieser Methode zurückgegeben werden, überhaupt Sinn. Sie finden dies sogar in der Dokumentation:

  

Die von dieser Methode zurückgegebenen Werte werden nur dann sinnvoll, wenn der Unterschied zwischen zwei solchen Werten, die innerhalb der gleichen Instanz einer Java Virtual Machine ermittelt wurden, berechnet wird.

Wenn Sie also die verstrichene Zeit Ihrer Methodenausführung oder Transaktionen messen und verarbeiten möchten, ist System.nanoTime() der richtige Weg. Zugegeben, es bietet nur einen nackten long -Wert, aber es ist nicht klar, welche Art von API-Unterstützung Sie wollen. Da Zeitpunkte hier irrelevant und sogar störend sind, haben Sie nur eine Dauer, die Sie in andere Zeiteinheiten oder, wenn Sie die neue Zeit-API verwenden möchten, können Sie ein Duration -Objekt mit Duration.ofNanos(long) , so dass Sie Duration-Werte hinzufügen und subtrahieren und vergleichen können, aber es gibt nicht viel mehr könntest du tun. Sie dürfen sie nicht mit Wand- oder kalenderbasierten Dauern mischen ...

Als letzte Anmerkung ist die Dokumentation bezüglich der Einschränkung ein wenig ungenau. Wenn Sie die Differenz zwischen zwei Werten berechnen, die von System.nanoTime() zurückgegeben werden, ist ein numerischer Überlauf an sich nicht schlecht. Da der Zähler einen nicht angegebenen Ursprung hat, liegt der Startwert Ihrer Operation möglicherweise nahe bei Long.MAX_VALUE , während der Endwert nahe bei Long.MIN_VALUE liegt, weil der JVM-Zähler einen Überlauf hatte. In diesem Fall verursacht die Berechnung der Differenz einen weiteren Überlauf, der einen korrekten Wert für die Differenz ergibt. Wenn Sie diese Differenz jedoch in einer signierten long speichern, kann sie maximal 2⁶³ Nanosekunden halten, wodurch die Differenz auf maximal 292 Jahre begrenzt wird. Wenn Sie sie jedoch als unsigned long behandeln, z. über Long.compareUnsigned und Long.toUnsignedString , Sie können sogar eine Dauer von 2⁶⁴ Nanosekunden verarbeiten Mit anderen Worten können Sie auf diese Weise bis zu 584 Jahre vergangener Zeit messen, wenn Ihr Computer nicht dazwischen einbricht ...

    
Holger 09.05.2016, 11:51
quelle
1

Ich würde empfehlen, getThreadCpuTime von ThreadMXBean zu verwenden (siehe auch Ссылка ). Wenn Sie die Ausführungszeit einer Methode messen wollen, sind Sie meistens nicht so sehr an der Wanduhr interessiert, sondern eher an der CPU-Ausführungszeit.

    
spa 06.05.2016 08:50
quelle

Tags und Links