При программировании анимации и небольших игр я узнал о невероятной важности Thread.sleep(n);
. Я полагаюсь на этот метод, чтобы сообщить операционной системе, когда моему приложению не понадобится ЦП, и с его помощью моя программа прогрессирует впредсказуемая скорость.
Моя проблема заключается в том, что JRE использует разные методы реализации этой функциональности в разных операционных системах.В основанных на UNIX (или под влиянием) ОС: таких, как Ubuntu и OS X, базовая реализация JRE использует хорошо функционирующую и точную систему для распределения процессорного времени между различными приложениями, что делает мою 2D-игру гладкой и без задержек,Тем не менее, в Windows 7 и более старых системах Microsoft распределение времени процессора, кажется, работает по-другому, и вы обычно возвращаете время процессора после заданного количества сна, которое варьируется примерно через 1-2 мс от целевого сна.Тем не менее, вы получаете случайные всплески дополнительного 10-20 мс времени сна.Это заставляет мою игру задерживаться каждые несколько секунд, когда это происходит.Я заметил, что эта проблема существует в большинстве Java-игр, которые я пробовал в Windows, при этом Minecraft является заметным примером.
Теперь я искал в Интернете, чтобы найти решение этой проблемы.Я видел много людей, использующих только Thread.yield();
вместо Thread.sleep(n);
, что безупречно работает за счет того, что используемое в настоящее время ядро ЦП получает полную нагрузку, независимо от того, сколько ЦП фактически требует ваша игра.Это не идеально подходит для игры на ноутбуках или рабочих станциях с высоким энергопотреблением, и это ненужный компромисс на компьютерах Mac и Linux.
Оглядываясь дальше, я нашел широко используемый метод исправления несоответствий во время сна, называемый«spin-sleep», где вы заказываете режим сна только по 1 мс за раз и проверяете согласованность с помощью метода System.nanoTime();
, который очень точен даже в системах Microsoft.Это помогает в течение 1-2 мс несогласованности сна, но не помогает против случайных всплесков + 10-20 мс несогласованности сна, поскольку это часто приводит к увеличению времени, затрачиваемого на то, чтобы один цикл моего цикла занял всевместе.
После долгих поисков я нашел загадочную статью Энди Малакова, которая очень помогла улучшить мой цикл: http://andy -malakov.blogspot.com / 2010/06 / alternative-to-threadsleep.html
Основываясь на его статье, я написал этот метод сна:
// 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
Я обычно ставлю примерно на 2 мс, а SPIN_YIELD_PRECISION
- примерно на 10000 нс для лучшей производительности на моем компьютере с Windows 7.
После множества тяжелых работ это самое лучшее, что я могу придумать.Итак, так как я все еще беспокоюсь об улучшении точности этого метода сна, и я все еще не удовлетворен производительностью, я хотел бы обратиться ко всем вам, хакерам и аниматорам Java-игр, за предложениями по лучшему решению дляПлатформа Windows.Могу ли я использовать платформу для Windows, чтобы сделать ее лучше?Меня не волнует наличие небольшого кода для конкретной платформы в моих приложениях, поскольку большая часть кода не зависит от ОС.
Я также хотел бы знать, есть ли кто-нибудь, кто знает о Microsoft и OracleРазрабатываете лучшую реализацию метода Thread.sleep(n);
, или каковы будущие планы Oracle по улучшению своей среды в качестве основы для приложений, требующих высокой точности синхронизации, таких как музыкальные программы и игры?
Спасибо всем за чтениемой длинный вопрос / статья.Я надеюсь, что некоторые люди могут найти мое исследование полезным!