Pregunta

Precisión vs.Precisión

Lo que me gustaría saber es si debo usar Sistema.currentTimeMillis() o Sistema.nanoTime() al actualizar las posiciones de mis objetos en mi juego?Su cambio de movimiento es directamente proporcional al tiempo transcurrido desde la última llamada y quiero ser lo más preciso posible.

He leído que existen algunos problemas graves de resolución de tiempo entre diferentes sistemas operativos (es decir, ¿Mac/Linux tiene una resolución de casi 1 ms mientras que Windows tiene una resolución de 50 ms?).Principalmente ejecuto mis aplicaciones en Windows y la resolución de 50 ms parece bastante inexacta.

¿Hay mejores opciones que las dos que enumeré?

¿Alguna sugerencia/comentario?

¿Fue útil?

Solución

Si solo está buscando mediciones extremadamente precisas del tiempo transcurrido , use System.nanoTime(). System.currentTimeMillis() le dará el tiempo transcurrido más preciso posible en milisegundos desde la época, pero <=> le dará un tiempo preciso de nanosegundos, en relación con algún punto arbitrario.

De la documentación de Java:

public static long nanoTime()
     

Devuelve el valor actual del temporizador del sistema disponible más preciso, en nanosegundos.

     

Este método solo puede usarse para   medir el tiempo transcurrido y no es   relacionado con cualquier otra noción de sistema   o la hora del reloj de pared. El valor devuelto   representa nanosegundos ya que algunos   tiempo fijo pero arbitrario (quizás en   el futuro, entonces los valores pueden ser   negativo). Este método proporciona   precisión de nanosegundos, pero no   necesariamente precisión de nanosegundos. No   se hacen garantías sobre cómo   Con frecuencia los valores cambian. Las diferencias   en llamadas sucesivas que abarcan mayor   de aproximadamente 292 años (2 63   nanosegundos) no con precisión   calcular el tiempo transcurrido debido a numérico   desbordamiento.

Por ejemplo, para medir cuánto tiempo lleva ejecutar un código:

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

Consulte también: Sistema JavaDoc. nanoTime () y JavaDoc System.currentTimeMillis () para más información.

Otros consejos

Dado que nadie más ha mencionado esto & # 8230;

No es seguro comparar los resultados de System.nanoTime() llamadas entre diferentes hilos. Incluso si los eventos de los hilos ocurren en un orden predecible, la diferencia en nanosegundos puede ser positiva o negativa.

System.currentTimeMillis() es seguro para usar entre hilos.

Actualizar por Arkady:He observado un comportamiento más correcto de System.currentTimeMillis() en Windows 7 en Oracle Java 8.La hora se devolvió con una precisión de 1 milisegundo.El código fuente en OpenJDK no ha cambiado, por lo que no sé qué causa el mejor comportamiento.


David Holmes de Sun publicó un artículo de blog hace un par de años que ofrece una visión muy detallada de las API de temporización de Java (en particular System.currentTimeMillis() y System.nanoTime()), cuándo le gustaría utilizar cuáles y cómo funcionan internamente.

Dentro de la máquina virtual del punto de acceso:Relojes, temporizadores y programación de eventos - Parte I - Windows

Un aspecto muy interesante del temporizador utilizado por Java en Windows para las API que tienen un parámetro de espera temporizado es que la resolución del temporizador puede cambiar dependiendo de qué otras llamadas API se hayan realizado: en todo el sistema (no solo en el proceso particular). .Muestra un ejemplo donde usar Thread.sleep() provocará este cambio de resolución.

System.nanoTime() no es compatible con JVM anteriores. Si eso le preocupa, quédese con currentTimeMillis

Con respecto a la precisión, estás casi en lo correcto. En ALGUNAS máquinas con Windows, currentTimeMillis() tiene una resolución de aproximadamente 10 ms (no 50 ms). No estoy seguro de por qué, pero algunas máquinas Windows son tan precisas como las máquinas Linux.

He usado GAGETimer en el pasado con éxito moderado.

Como han dicho otros, currentTimeMillis es la hora del reloj, que cambia debido al horario de verano, los usuarios cambian la configuración de la hora, los segundos intermedios y la sincronización de la hora de Internet. Si su aplicación depende de valores de tiempo transcurrido que aumentan monotónicamente, es posible que prefiera nanoTime.

Puedes pensar que los jugadores no estarán jugando con la configuración de tiempo durante el juego, y tal vez tengas razón. Pero no subestimes la interrupción debido a la sincronización horaria de Internet, o quizás a los usuarios de escritorio remoto. La API nanoTime es inmune a este tipo de interrupción.

Si desea usar la hora del reloj, pero evita las discontinuidades debido a la sincronización horaria de Internet, puede considerar un cliente NTP como Meinberg, que " sintoniza " la frecuencia del reloj para ponerlo a cero, en lugar de simplemente restablecer el reloj periódicamente.

Hablo por experiencia personal. En una aplicación meteorológica que desarrollé, recibía picos de velocidad del viento que ocurrían al azar. Me tomó un tiempo darme cuenta de que mi base de tiempo estaba siendo interrumpida por el comportamiento de la hora del reloj en una PC típica. Todos mis problemas desaparecieron cuando comencé a usar nanoTime. La consistencia (monotonicidad) era más importante para mi aplicación que la precisión bruta o la precisión absoluta.

Sí, si se requiere tal precisión, utilice System.nanoTime(), pero tenga en cuenta que necesita una JVM Java 5+.

En mis sistemas XP, veo la hora del sistema informada al menos a 100 microsegundos 278 nanosegundos utilizando el siguiente código:

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

He tenido una buena experiencia con nanotime . Proporciona tiempo de reloj de pared como dos largos (segundos desde la época y nanosegundos dentro de ese segundo), utilizando una biblioteca JNI. Está disponible con la parte JNI precompilada para Windows y Linux.

Para gráficos del juego & amp; actualizaciones de posición fluidas, use System.nanoTime() en lugar de System.currentTimeMillis(). Cambié de currentTimeMillis () a nanoTime () en un juego y obtuve una mejora visual importante en la suavidad del movimiento.

Si bien un milisegundo puede parecer que ya debería ser preciso, visualmente no lo es. Los factores que nanoTime() pueden mejorar incluyen:

  • posicionamiento preciso de píxeles por debajo de la resolución del reloj de pared
  • capacidad de anti-alias entre píxeles, si lo desea
  • Inexactitud del reloj de pared de Windows
  • fluctuación del reloj (inconsistencia de cuándo el reloj de pared realmente avanza)

Como sugieren otras respuestas, nanoTime tiene un costo de rendimiento si se le llama repetidamente: sería mejor llamarlo solo una vez por fotograma y usar el mismo valor para calcular el fotograma completo.

System.currentTimeMillis() no es seguro durante el tiempo transcurrido porque este método es sensible a los cambios de reloj en tiempo real del sistema. Deberías usar System.nanoTime. Consulte la ayuda del sistema Java:

Acerca del método nanoTime:

  

.. Este método proporciona precisión en nanosegundos, pero no necesariamente   resolución de nanosegundos (es decir, con qué frecuencia cambia el valor): no   se hacen garantías excepto que la resolución es al menos tan buena como   el de currentTimeMillis () ..

Si usa <=> su tiempo transcurrido puede ser negativo (Volver < - al futuro)

una cosa aquí es la inconsistencia del método nanoTime. no proporciona valores muy consistentes para la misma entrada. actualTimeMillis funciona mucho mejor en términos de rendimiento y consistencia, y además, aunque no es tan preciso como nanoTime, tiene un valor inferior margen de error, y por lo tanto más precisión en su valor. Por lo tanto, le sugiero que use currentTimeMillis

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top