При программировании анимаций и небольших игр я узнал невероятную важность Thread.sleep(n);
. Я полагаюсь на этот метод, чтобы сообщить операционной системе, когда моему приложению не понадобится какой-либо процессор, и используя это, чтобы моя программа продвигалась в прогнозируемая скорость.
Моя проблема заключается в том, что JRE использует различные методы реализации этой функции в разных операционных системах. В ОС UNIX (или влияющих) ОС, таких как Ubuntu и OS X, базовая реализация JRE использует хорошо функционирующую и точную систему для распределения времени CPU для разных приложений, и поэтому делает мою 2D-игру гладкой и беззаботной, Однако в Windows 7 и более ранних системах Microsoft распределение времени процессора по-разному работает, и вы обычно возвращаете свое процессорное время после заданного количества сна, варьируя примерно от 1-2 мс от целевого сна. Тем не менее, вы получаете случайные всплески дополнительных 10-20 мс времени сна. Это заставляет мою игру отставать каждые несколько секунд, когда это происходит. Я заметил, что эта проблема существует в большинстве игр Java, которые я пробовал в Windows, что является заметным примером Minecraft.
Теперь я искал в Интернете, чтобы найти решение этой проблемы. Я видел много людей, использующих только Thread.yield();
вместо Thread.sleep(n);
, который работает безупречно за счет того, что в настоящее время процессорное ядро получает полную нагрузку, независимо от того, сколько CPU вам действительно нужна. Это не идеально подходит для игры на ноутбуках или на высокопроизводительных рабочих станциях, что является ненужным компромиссом на компьютерах Mac и Linux.
Оглядываясь дальше, я нашел широко используемый метод исправления несоответствий времени сна, называемый "спин-сон", где вы заказываете только сон за 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
примерно до 10 000 нс для лучшей производительности на моей машине с Windows 7.
После тяжелой работы, это самое лучшее, что я могу придумать. Поэтому, поскольку я все еще забочусь о повышении точности этого метода сна, и я до сих пор не доволен производительностью, я хотел бы обратиться ко всем вам, хакерам и аниматорам Java, там, где есть предложения по лучшему решению для Платформа Windows. Могу ли я использовать платформенный способ для Windows, чтобы сделать его лучше? Я не забочусь о том, чтобы в моих приложениях был написан небольшой код для конкретной платформы, если большая часть кода не зависит от ОС.
Я также хотел бы знать, есть ли кто-нибудь, кто знает о Microsoft и Oracle, о разработке более эффективной реализации метода Thread.sleep(n);
или о том, какие планы Oracle планируют улучшить свою среду в качестве основы для приложений, требующих высокой точности синхронизации, таких как музыкальное программное обеспечение и игры?
Спасибо, что прочитали мой длинный вопрос/статью. Я надеюсь, что некоторые люди могут найти мое исследование полезным!