Domanda

Precisione vs. Precisione

Quello che vorrei sapere è se dovrei usare System.currentTimeMillis () o System.nanoTime () quando aggiorno le posizioni dei miei oggetti nel mio gioco? Il loro cambio di movimento è direttamente proporzionale al tempo trascorso dall'ultima chiamata e voglio essere il più preciso possibile.

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

Ci sono opzioni migliori delle due che ho elencato?

Qualche suggerimento / commento?

È stato utile?

Soluzione

Se stai solo cercando misurazioni estremamente precise del tempo trascorso , usa System.nanoTime(). System.currentTimeMillis() ti darà il tempo trascorso più preciso possibile in millisecondi dall'epoca, ma <=> ti dà un tempo di nanosecondi, 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 lo è   correlato a qualsiasi altra nozione di sistema   o l'ora dell'orologio da parete. Il valore restituito   rappresenta nanosecondi da alcuni   tempo fisso ma arbitrario (forse in   il futuro, quindi i valori potrebbero essere   negativo). Questo metodo fornisce   precisione dei nanosecondi, ma non   precisione necessariamente dei nanosecondi. No   vengono fornite garanzie su come   i valori cambiano frequentemente. differenze   nelle chiamate successive che si estendono di più   di circa 292 anni (2 63   nanosecondi) non sarà preciso   calcolare il tempo trascorso a causa di valori numerici   trabocco.

Ad esempio, per misurare quanto tempo richiede l'esecuzione del codice:

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.

Altri suggerimenti

Dato che nessun altro ha menzionato questo & # 8230;

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

System.currentTimeMillis() è sicuro da usare tra i thread.

Aggiornamento di Arkadiy : ho osservato un comportamento più corretto di System.currentTimeMillis() su Windows 7 in Oracle Java 8. Il tempo è stato restituito con precisione di 1 millisecondo. 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 di blog un paio di anni fa che ha uno sguardo molto dettagliato alle API di temporizzazione Java (in particolare System.nanoTime() e Thread.sleep()), quando si desidera utilizzare quali e come funzionano internamente.

All'interno della VM Hotspot: Orologi, timer ed eventi di pianificazione - Parte I - Windows

Un aspetto molto interessante del timer usato da Java su Windows per le API che hanno un parametro di attesa a tempo è che la risoluzione del timer può cambiare a seconda di quali altre chiamate API potrebbero essere state fatte - a livello di sistema (non solo nel processo particolare). Mostra un esempio in cui l'uso di <=> causerà questo cambiamento di risoluzione.

System.nanoTime() non è supportato nelle JVM precedenti. Se questo è un problema, mantieni currentTimeMillis

Per quanto riguarda la precisione, hai quasi ragione. Su ALCUNI computer Windows, currentTimeMillis() ha una risoluzione di circa 10 ms (non 50 ms). Non sono sicuro del perché, ma alcune macchine Windows sono accurate 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, degli utenti che cambiano le impostazioni dell'ora, dei secondi bisestili e della sincronizzazione dell'ora di Internet. Se la tua app dipende dall'aumento monotonico dei valori di tempo trascorso, 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 l'interruzione dovuta alla sincronizzazione dell'ora di Internet o agli utenti desktop remoti. L'API nanoTime è immune da questo tipo di interruzione.

Se si desidera utilizzare l'ora, ma evitare discontinuità dovute alla sincronizzazione dell'ora di Internet, è possibile prendere in considerazione un client NTP come Meinberg, che " sintonizza " la frequenza di clock per azzerarlo, invece di reimpostare periodicamente l'orologio.

Parlo per esperienza personale. In un'applicazione meteorologica 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 stata interrotta dal comportamento dell'orologio su un tipico PC. Tutti i miei problemi sono scomparsi quando ho iniziato a utilizzare nanoTime. La coerenza (monotonia) era più importante per la mia applicazione rispetto alla precisione grezza o alla precisione assoluta.

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

Sui miei sistemi XP, vedo l'ora di sistema riportata almeno 100 microsecondi 278 nanosecondi utilizzando 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 dell'orologio da parete come due lunghi (secondi dall'epoca e nanosecondi entro quel secondo), usando una libreria JNI. È disponibile con la parte JNI precompilata sia per Windows che per Linux.

Per la grafica di gioco & amp; aggiornamenti della posizione regolare, utilizzare System.nanoTime() anziché System.currentTimeMillis(). Sono passato da currentTimeMillis () a nanoTime () in un gioco e ho ottenuto un notevole miglioramento visivo della scorrevolezza dei movimenti.

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

  • posizionamento preciso dei pixel al di sotto della risoluzione dell'orologio da parete
  • possibilità di anti-alias tra pixel, se lo desideri
  • Inesattezza dell'orologio da parete di Windows
  • clock jitter (incoerenza rispetto al momento in cui l'orologio da parete scorre in avanti)

Come suggeriscono altre risposte, nanoTime ha un costo in termini di prestazioni se chiamato ripetutamente: sarebbe meglio chiamarlo una sola volta per frame e usare lo stesso valore per calcolare l'intero frame.

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

Informazioni sul metodo nanoTime:

  

.. Questo metodo fornisce precisione in nanosecondi, ma non necessariamente   risoluzione in nanosecondi (ovvero con quale frequenza cambia il valore) - no   vengono fornite garanzie salvo che la risoluzione è almeno pari a   quello di currentTimeMillis () ..

Se si utilizza <=> il tempo trascorso può essere negativo (Indietro < - al futuro)

una cosa qui è l'incoerenza del metodo nanoTime.it non fornisce 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 valore inferiore margine di errore, e quindi maggiore precisione nel suo valore. pertanto suggerirei di utilizzare currentTimeMillis

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top