System.currentTimeMillis vs System.nanoTime

Accuratezza vs. Precisione

Quello che vorrei sapere è se dovrei usare System.currentTimeMillis () o System.nanoTime () quando aggiorno le posizioni del mio object nel mio gioco? Il loro cambiamento nel movimento è direttamente proporzionale al tempo trascorso dall’ultima chiamata e voglio essere il più preciso ansible.

Ho letto che ci sono alcuni gravi problemi di risoluzione temporale tra diversi sistemi operativi (ovvero che Mac / Linux hanno una risoluzione di quasi 1 ms mentre Windows ha una risoluzione di 50ms ??). Sto eseguendo principalmente le mie app su Windows e la risoluzione di 50 ms sembra piuttosto imprecisa.

Ci sono opzioni migliori rispetto alle due che ho elencato?

Qualche suggerimento / commento?

Se stai solo cercando misure estremamente precise del tempo trascorso , usa System.nanoTime() . System.currentTimeMillis() ti darà il tempo più preciso ansible trascorso in millisecondi dall’epoca, ma System.nanoTime() ti dà un tempo preciso di nanosecondo, relativo ad un punto arbitrario.

Dalla documentazione Java:

 public static long nanoTime() 

Restituisce il valore corrente del timer di sistema disponibile più preciso, in nanosecondi.

Questo metodo può essere utilizzato solo per misurare il tempo trascorso e non è correlato a nessun’altra nozione di tempo del sistema o dell’orologio a muro. Il valore restituito rappresenta i nanosecondi poiché alcuni tempi fissi ma arbitrari (forse in futuro, quindi i valori potrebbero essere negativi). Questo metodo fornisce precisione in nanosecondi, ma non necessariamente precisione in nanosecondi. Non viene fornita alcuna garanzia sulla frequenza con cui i valori cambiano. Le differenze nelle chiamate successive che si estendono per oltre 292 anni (2 63 nanosecondi) non calcolano in modo accurato il tempo trascorso a causa dell’overflow numerico.

Ad esempio, per misurare la durata del codice da eseguire:

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

Vedi anche: JavaDoc System.nanoTime () e JavaDoc System.currentTimeMillis () per maggiori informazioni.

Thread-Safety

Dal momento che nessun altro ha menzionato questo …

Non sicuro

Non è sicuro confrontare i risultati delle chiamate System.nanoTime() tra diversi thread. Anche se gli eventi dei thread avvengono in un ordine prevedibile, la differenza in nanosecondi può essere positiva o negativa.

Sicuro

System.currentTimeMillis() è sicuro per l’uso tra i thread.

Aggiornamento di Arkadiy : Ho osservato un comportamento più corretto di System.currentTimeMillis() su Windows 7 in Oracle Java 8. L’ora è stata restituita con 1 millisecondo di precisione. Il codice sorgente in OpenJDK non è cambiato, quindi non so quale sia la causa del comportamento migliore.


David Holmes di Sun ha pubblicato un articolo sul blog un paio di anni fa che ha un aspetto molto dettagliato delle API di temporizzazione Java (in particolare System.currentTimeMillis() e System.nanoTime() ), quando si vorrebbe usare quale e come lavorare internamente.

All’interno della VM Hotspot: Orologi, timer e eventi di programmazione – Parte I – Windows

Un aspetto molto interessante del timer utilizzato da Java su Windows per le API che hanno un parametro di attesa temporizzato è che la risoluzione del timer può cambiare a seconda di quali altre chiamate API possono essere state fatte – a livello di sistema (non solo nel particolare processo) . Mostra un esempio in cui l’uso di Thread.sleep() causerà questa modifica della risoluzione.

System.nanoTime() non è supportato nelle JVM più vecchie. Se questo è un problema, continua con currentTimeMillis

Per quanto riguarda la precisione, sei quasi corretto. Su alcune macchine Windows, currentTimeMillis() ha una risoluzione di circa 10ms (non 50ms). Non sono sicuro del perché, ma alcune macchine Windows sono precise quanto le macchine Linux.

Ho usato GAGETimer in passato con moderato successo.

Come altri hanno già detto, currentTimeMillis è l’ora dell’orologio, che cambia a causa dell’ora legale, gli utenti che cambiano le impostazioni dell’ora, i secondi bisestili e la sincronizzazione dell’ora internet. Se la tua app dipende da valori di tempo trascorso in aumento monotono, potresti preferire nanoTime.

Potresti pensare che i giocatori non giocheranno con le impostazioni del tempo durante il gioco, e forse avresti ragione. Ma non sottovalutare le interruzioni dovute alla sincronizzazione dell’orario internet, o forse agli utenti desktop remoti. L’API nanoTime è immune da questo tipo di interruzione.

Se si desidera utilizzare l’ora dell’orologio, ma evitare le discontinuità dovute alla sincronizzazione dell’orario Internet, si potrebbe prendere in considerazione un client NTP come Meinberg, che “sintonizza” la frequenza di clock per azzerarla, invece di reimpostare periodicamente l’orologio.

Parlo per esperienza personale. In un’applicazione meteo che ho sviluppato, stavo ottenendo picchi di velocità del vento casuali. Mi ci è voluto un po ‘per capire che la mia base dei tempi era interrotta dal comportamento dell’orologio su un PC tipico. Tutti i miei problemi sono scomparsi quando ho iniziato a usare nanoTime. La coerenza (monotonicità) era più importante per la mia applicazione della precisione grezza o dell’accuratezza assoluta.

Sì, se è richiesta tale precisione utilizzare System.nanoTime() , ma tenere presente che si richiede quindi una JVM Java 5+.

Nei miei sistemi XP, vedo il tempo di sistema riportato ad almeno 100 microsecondi 278 nanosecondi usando il seguente codice:

 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)); } } 

Ho avuto una buona esperienza con nanotime . Fornisce il tempo di wall-wall come due lunghi (secondi dall’epoca e dai nanosecondi entro quel secondo), usando una libreria JNI. È disponibile con la parte JNI precompilata per Windows e Linux.

Per la grafica di gioco e gli aggiornamenti di posizione, usa System.nanoTime() piuttosto che System.currentTimeMillis() . Sono passato da currentTimeMillis () a nanoTime () in un gioco e ho ottenuto un notevole miglioramento visivo nella fluidità del movimento.

Mentre un millisecondo può sembrare come se fosse già preciso, visivamente non lo è. I fattori nanoTime() possono migliorare includono:

  • posizionamento preciso dei pixel al di sotto della risoluzione del wall-clock
  • possibilità di anti-alias tra pixel, se vuoi
  • Annotazione dell’orologio a muro di Windows
  • clock jitter (incoerenza di quando il wall-clock in realtà fa il segno di spunta in avanti)

Come suggeriscono altre risposte, nanoTime ha un costo in termini di prestazioni se chiamato più volte – sarebbe meglio chiamarlo solo una volta per fotogramma, e usare lo stesso valore per calcolare l’intero fotogramma.

System.currentTimeMillis() non è sicuro per il tempo trascorso poiché questo metodo è sensibile alle modifiche dell’orologio in tempo reale del sistema. Dovresti usare System.nanoTime . Fare riferimento alla guida del sistema Java:

Informazioni sul metodo nanoTime:

.. Questo metodo fornisce una precisione di nanosecondi, ma non necessariamente una risoluzione di nanosecondi (ovvero, la frequenza con cui varia il valore) – nessuna garanzia è fatta tranne che la risoluzione è almeno buona come quella di currentTimeMillis ().

Se si utilizza System.currentTimeMillis() il tempo trascorso può essere negativo (Indietro < - al futuro)

una cosa qui è l’inconsistenza del metodo nanoTime.it non dà valori molto coerenti per lo stesso input.currentTimeMillis fa molto meglio in termini di prestazioni e coerenza, e anche, sebbene non così preciso come nanoTime, ha un margine di errore più basso e quindi più precisione nel suo valore. quindi suggerirei di usare currentTimeMillis