una sueño recomendadas que persona oms minimo horas hora dormir debe cuanto cuantas como anciano adolescente java animation game-engine

java - recomendadas - Investigación del cálculo óptimo del tiempo de sueño en el bucle del juego.



dormir 7 horas (5)

Las cosas de tiempo son notoriamente malas en las ventanas. Este artículo es un buen lugar para comenzar. No estoy seguro de si le importa, pero también tenga en cuenta que también puede haber problemas peores (especialmente con System.nanoTime) en sistemas virtuales (cuando Windows es el sistema operativo invitado).

Al programar animaciones y pequeños juegos, he llegado a conocer la increíble importancia de Thread.sleep(n); Confío en este método para indicar al sistema operativo cuándo mi aplicación no necesitará una CPU, y usar esto hace que mi programa progrese a una velocidad predecible.

Mi problema es que el JRE utiliza diferentes métodos de implementación de esta funcionalidad en diferentes sistemas operativos. En sistemas operativos basados ​​en UNIX (o influenciados) como Ubuntu y OS X, la implementación JRE subyacente utiliza un sistema preciso y que funciona bien para distribuir el tiempo de CPU a diferentes aplicaciones, lo que hace que mi juego 2D sea suave y sin retrasos . Sin embargo, en Windows 7 y sistemas Microsoft anteriores, la distribución del tiempo de CPU parece funcionar de manera diferente, y por lo general recupera el tiempo de CPU después de la cantidad determinada de sueño, variando con aproximadamente 1-2 ms desde el sueño objetivo. Sin embargo, usted obtiene ráfagas ocasionales de 10 a 20 ms de tiempo de sueño. Esto hace que mi juego se retrase una vez cada pocos segundos cuando esto sucede. He notado que este problema existe en la mayoría de los juegos Java que he probado en Windows, siendo Minecraft un ejemplo notable.

Ahora, he estado buscando en Internet para encontrar una solución a este problema. He visto a mucha gente usar solo Thread.yield(); en lugar de Thread.sleep(n); , que funciona a la perfección a costa de que el núcleo de la CPU utilizado actualmente tenga plena carga, independientemente de la cantidad de CPU que su juego realmente necesite. Esto no es ideal para jugar su juego en computadoras portátiles o estaciones de trabajo de alto consumo de energía, y es una compensación innecesaria en sistemas Mac y Linux.

Mirando a mi alrededor, encontré un método comúnmente usado para corregir las inconsistencias del tiempo de sueño llamado "spin-sleep", en el que solo ordena el sueño por 1 ms a la vez y verifica la consistencia utilizando System.nanoTime(); Método, que es muy preciso incluso en los sistemas de Microsoft. Esto ayuda a los 1-2 ms normales de la inconsistencia del sueño, pero no lo ayudará contra las ráfagas ocasionales de + 10-20 ms de la inconsistencia del sueño, ya que esto a menudo resulta en más tiempo que un ciclo de mi ciclo debería tomar todo juntos.

Después de un montón de miradas, encontré este artículo críptico de Andy Malakov, que me ayudó mucho a mejorar mi bucle: http://andy-malakov.blogspot.com/2010/06/alternative-to-threadsleep.html

Basado en su artículo escribí este método de sueño:

// Variables for calculating optimal sleep time. In nanoseconds (1s = 10^-9ms). private long timeBefore = 0L; private long timeSleepEnd, timeLeft; // The estimated game update rate. private double timeUpdateRate; // The time one game loop cycle should take in order to reach the max FPS. private long timeLoop; private void sleep() throws InterruptedException { // Skip first game loop cycle. if (timeBefore != 0L) { // Calculate optimal game loop sleep time. timeLeft = timeLoop - (System.nanoTime() - timeBefore); // If all necessary calculations took LESS time than given by the sleepTimeBuffer. Max update rate was reached. if (timeLeft > 0 && isUpdateRateLimited) { // Determine when to stop sleeping. timeSleepEnd = System.nanoTime() + timeLeft; // Sleep, yield or keep the thread busy until there is not time left to sleep. do { if (timeLeft > SLEEP_PRECISION) { Thread.sleep(1); // Sleep for approximately 1 millisecond. } else if (timeLeft > SPIN_YIELD_PRECISION) { Thread.yield(); // Yield the thread. } if (Thread.interrupted()) { throw new InterruptedException(); } timeLeft = timeSleepEnd - System.nanoTime(); } while (timeLeft > 0); } // Save the calculated update rate. timeUpdateRate = 1000000000D / (double) (System.nanoTime() - timeBefore); } // Starting point for time measurement. timeBefore = System.nanoTime(); }

SLEEP_PRECISION lo general pongo a aproximadamente 2 ms, y SPIN_YIELD_PRECISION a aproximadamente 10 000 ns para obtener el mejor rendimiento en mi máquina con Windows 7.

Después de un montón de trabajo duro, esto es lo mejor que puedo encontrar. Por lo tanto, como todavía me importa mejorar la precisión de este método de suspensión y aún no estoy satisfecho con el rendimiento, me gustaría hacer un llamamiento a todos los hackers y animadores de juegos Java para que me den sugerencias sobre una mejor solución para el Plataforma de Windows. ¿Podría usar una forma específica de plataforma en Windows para hacerlo mejor? No me importa tener un pequeño código específico de plataforma en mis aplicaciones, siempre que la mayoría del código sea independiente del sistema operativo.

También me gustaría saber si hay alguien que sepa que Microsoft y Oracle están trabajando en una mejor implementación de Thread.sleep(n); ¿Cuál es el método, o cuáles son los planes futuros de Oracle para mejorar su entorno como la base de las aplicaciones que requieren una alta precisión de tiempo, como software y juegos de música?

Gracias a todos por leer mi larga pregunta / artículo. ¡Espero que algunas personas encuentren útil mi investigación!


Podría usar un temporizador cíclico asociado con un mutex . Esta es IHMO la forma más eficiente de hacer lo que quiere. Pero debería pensar en omitir marcos en caso de que la computadora se demore (puede hacerlo con otra exclusión mutua sin bloqueo en el código del temporizador).

Edición: Algunos pseudocódigo para aclarar.

Código del temporizador:

While(true): if acquireIfPossible(mutexSkipRender): release(mutexSkipRender) release(mutexRender)

Código de reposo:

acquire(mutexSkipRender) acquire(mutexRender) release(mutexSkipRender)

Valores iniciales:

mutexSkipRender = 1 mutexRender = 0

Edición : valores de inicialización corregidos.

El siguiente código funciona bastante bien en Windows (realiza un bucle a exactamente 50 fps con una precisión de milisegundos)

import java.util.Date; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Semaphore; public class Main { public static void main(String[] args) throws InterruptedException { final Semaphore mutexRefresh = new Semaphore(0); final Semaphore mutexRefreshing = new Semaphore(1); int refresh = 0; Timer timRefresh = new Timer(); timRefresh.scheduleAtFixedRate(new TimerTask() { @Override public void run() { if(mutexRefreshing.tryAcquire()) { mutexRefreshing.release(); mutexRefresh.release(); } } }, 0, 1000/50); // The timer is started and configured for 50fps Date startDate = new Date(); while(true) { // Refreshing loop mutexRefresh.acquire(); mutexRefreshing.acquire(); // Refresh refresh += 1; if(refresh % 50 == 0) { Date endDate = new Date(); System.out.println(String.valueOf(50.0*1000/(endDate.getTime() - startDate.getTime())) + " fps."); startDate = new Date(); } mutexRefreshing.release(); } } }


Sus opciones son limitadas y dependen de lo que desea hacer exactamente. Su fragmento de código menciona el máximo de FPS, pero el máximo de FPS requeriría que nunca duerma, así que no estoy completamente seguro de qué es lo que pretende con eso. Sin embargo, ninguno de los controles de suspensión o rendimiento va a hacer ninguna diferencia en la mayoría de las situaciones problemáticas: si alguna otra aplicación necesita ejecutarse ahora y el sistema operativo no quiere volver a cambiar pronto, no importa cuál de ellas Cuando llame, obtendrá el control cuando el sistema operativo decida hacerlo, lo que seguramente será más de 1 ms en el futuro. Sin embargo, el sistema operativo se puede convencer para que haga los conmutadores con más frecuencia: Win32 tiene el llamado timeBeginPeriod para este propósito, que puede utilizar de alguna manera. Pero hay una buena razón para no cambiar con demasiada frecuencia: es menos eficiente.

Lo mejor que se puede hacer, aunque algo más complejo, es ir por un circuito de juego que no requiere actualizaciones en tiempo real, sino que realiza actualizaciones lógicas a intervalos fijos (por ejemplo, 20 veces por segundo) y se procesa siempre que sea posible (tal vez con tiempos de espera breves arbitrarios para liberar CPU para otras aplicaciones, si no se ejecutan en pantalla completa). Al almacenar en búfer un estado lógico pasado y uno actual, puede interpolar entre ellos para que el renderizado se vea tan suave como si estuviera haciendo actualizaciones lógicas cada vez. Para obtener más información sobre este enfoque, puede ver el artículo Fix Your Timestep .

También me gustaría saber si hay alguien que sepa que Microsoft y Oracle están trabajando en una mejor implementación de Thread.sleep (n); ¿Cuál es el método, o cuáles son los planes futuros de Oracle para mejorar su entorno como la base de las aplicaciones que requieren una alta precisión de tiempo, como software y juegos de música?

No, esto no va a pasar. Recuerde, dormir es solo un método que dice cuánto tiempo desea que su programa esté dormido. No es una especificación de cuándo o cuándo debe despertarse, y nunca lo será. Por definición, cualquier sistema con funcionalidad de suspensión y rendimiento es un sistema multitarea, donde deben tenerse en cuenta los requisitos de otras tareas, y el sistema operativo siempre recibe la última llamada en la programación de esto. La alternativa no funcionaría de manera confiable, porque si un programa pudiera exigir que se reactivara en un momento preciso de su elección, podría privar a otros procesos de la potencia de la CPU. (Por ejemplo, un programa que generó un subproceso en segundo plano y tenía ambos subprocesos que realizan 1 ms de trabajo y que llama al modo de espera (1) al final podría turnarse para acaparar un núcleo de CPU). Por lo tanto, para un programa de espacio de usuario, el modo de suspensión (y la funcionalidad) like it) siempre será un límite inferior, nunca un límite superior. Hacer algo mejor que eso requiere que el propio sistema operativo permita que ciertas aplicaciones se apropien de la programación, y esta no es una característica deseable en los sistemas operativos para hardware de consumo (si bien es una característica común y útil para aplicaciones industriales).


Thread.Sleep dice que tu aplicación no necesita más tiempo. Esto significa que, en el peor de los casos, tendrá que esperar un segmento de hilo completo (aproximadamente 40 ms).

Ahora, en los casos difíciles, cuando un controlador o algo lleva más tiempo, es posible que deba esperar 120 ms (3 * 40 ms) para que Thread.Sleep no sea el camino a seguir. Vaya de otra manera, como registrar una devolución de llamada de 1 ms e iniciar el código de sorteo de muy X devoluciones de llamada.

(Esto está en Windows, yo usaría herramientas de Multimedia para obtener esas devoluciones de llamada de resolución de 1 ms)


Thread.sleep es impreciso y hace que la animación sea nerviosa la mayor parte del tiempo.

Si lo reemplaza por completo con Thread.yield obtendrá un FPS sólido sin demora ni jitter, sin embargo, el uso de la CPU aumenta considerablemente. Me mudé a Thread.yield hace mucho tiempo.

Este problema ha sido discutido en los foros de desarrollo de juegos Java durante años.