Precisión vs. Precisión
Lo que me gustaría saber es si debo usar System.currentTimeMillis () o System.nanoTime () al actualizar las posiciones de mi objeto 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 hay algunos problemas serios de resolución de tiempo entre diferentes sistemas operativos (es decir, que Mac / Linux tienen una resolución de casi 1 ms mientras que Windows tiene una resolución de 50 ms). Principalmente estoy ejecutando 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?
java
timer
time-precision
mmcdole
fuente
fuente
nanoTime
es significativamente más preciso que currentTimeMillis, pero también es una llamada relativamente costosa.currentTimeMillis()
se ejecuta en unos pocos (5-6) relojes de CPU, nanoTime depende de la arquitectura subyacente y puede tener más de 100 relojes de CPU.System.currentTimeMillis()
: pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.htmlRespuestas:
Si solo está buscando mediciones extremadamente precisas del tiempo transcurrido , úselas
System.nanoTime()
.System.currentTimeMillis()
le dará el tiempo transcurrido más preciso posible en milisegundos desde la época, peroSystem.nanoTime()
le dará un tiempo preciso de nanosegundos, en relación con algún punto arbitrario.De la documentación de Java:
Por ejemplo, para medir cuánto tiempo lleva ejecutar un código:
Consulte también: JavaDoc System.nanoTime () y JavaDoc System.currentTimeMillis () para obtener más información.
fuente
currentTimeMillis
cambiaría debido al horario de verano? El interruptor DST no cambia el número de segundos después de la época. Puede ser un "reloj de pared" pero está basado en UTC. Debe determinar en función de su configuración de zona horaria y horario de verano lo que eso se traduce para su hora local (o utilizar otras utilidades de Java para hacerlo por usted).Como nadie más ha mencionado esto ...
No es seguro comparar los resultados de las
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.fuente
The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.
nanoTime()
dice: todas las invocaciones de este método utilizan un mismo origen en una instancia de una máquina virtual Java; Es probable que otras instancias de máquinas virtuales utilicen un origen diferente. lo que significa que no devuelven los mismos a través de las discusiones.Actualización de Arkadiy : He observado un comportamiento más correcto
System.currentTimeMillis()
en Windows 7 en Oracle Java 8. El tiempo 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 en el blog hace un par de años que tiene una visión muy detallada de las API de temporización de Java (en particular
System.currentTimeMillis()
ySystem.nanoTime()
), cuándo querría usar cuáles y cómo funcionan internamente.Dentro de la VM Hotspot: relojes, temporizadores y eventos de programación - Parte I - Windows
Un aspecto muy interesante del temporizador utilizado por Java en Windows para las API que tienen un parámetro de espera cronometrado es que la resolución del temporizador puede cambiar dependiendo de qué otras llamadas a la API se hayan realizado: en todo el sistema (no solo en el proceso en particular) . Muestra un ejemplo en el que el uso
Thread.sleep()
provocará un cambio en esta resolución.fuente
GetSystemTimeAsFileTime
en que funcionó en XP vs 7. Vea aquí para más detalles (tl; dr se volvió más preciso ya que todo el sistema introdujo algunos métodos de sincronización más precisos).System.nanoTime()
no es compatible con JVM anteriores. Si eso es una preocupación, quédate concurrentTimeMillis
En cuanto 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 con Windows son tan precisas como las máquinas con Linux.He usado GAGETimer en el pasado con un éxito moderado.
fuente
Como otros han dicho, 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.
Podrías pensar que los jugadores no estarán jugando con los ajustes 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 utilizar la hora del reloj, pero evita las discontinuidades debido a la sincronización horaria de Internet, puede considerar un cliente NTP como Meinberg, que "ajusta" la frecuencia del reloj para ponerlo a cero, en lugar de simplemente reiniciar 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.
fuente
System.currentTimeMillis()
informa el tiempo transcurrido (en milisegundos) desde la época de Unix / Posix, que es la medianoche del 1 de enero de 1970 UTC. Como UTC nunca se ajusta para el horario de verano, este valor no se compensará cuando las zonas horarias locales agreguen o sometan compensaciones a los horarios locales para el horario de verano. Además, la escala de tiempo de Java suaviza los segundos bisiestos para que los días sigan teniendo 86.400 segundos.Sí, si se requiere tal precisión
System.nanoTime()
, pero tenga en cuenta que necesita una JVM Java 5+.En mis sistemas XP, veo el tiempo del sistema informado al menos a
100 microsegundos y278 nanosegundos usando el siguiente código:fuente
Para gráficos de juegos y actualizaciones de posición fluidas, use en
System.nanoTime()
lugar deSystem.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:Como sugieren otras respuestas, nanoTime tiene un costo de rendimiento si se llama repetidamente: sería mejor llamarlo solo una vez por fotograma y usar el mismo valor para calcular el fotograma completo.
fuente
He tenido 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.
fuente
System.currentTimeMillis()
no es seguro para el tiempo transcurrido porque este método es sensible a los cambios de reloj en tiempo real del sistema. Deberías usarSystem.nanoTime
. Consulte la ayuda del sistema Java:Sobre el método nanoTime:
Si usa
System.currentTimeMillis()
su tiempo transcurrido puede ser negativo (Volver <- al futuro)fuente
Una cosa aquí es la inconsistencia del método nanoTime. No proporciona valores muy consistentes para la misma entrada. CurrentTimeMillis funciona mucho mejor en términos de rendimiento y consistencia, y además, aunque no es tan preciso como nanoTime, tiene un margen de error más bajo y, por lo tanto, más precisión en su valor. Por lo tanto, sugeriría que use currentTimeMillis
fuente