Точность против точность
Я хотел бы знать, должен ли я использовать System.currentTimeMillis () или System.nanoTime () при обновлении позиций моего объекта в моей игре? Их изменение в движении прямо пропорционально времени, прошедшему с момента последнего звонка, и я хочу быть максимально точным.
Я читал, что существуют некоторые серьезные проблемы с разрешением времени между различными операционными системами (а именно, что Mac / Linux имеют разрешение почти 1 мс, в то время как Windows имеет разрешение 50 мс ??). Я в основном запускаю свои приложения на Windows, и разрешение 50 мс кажется довольно неточным.
Есть ли лучшие варианты, чем два, которые я перечислил?
Любые предложения / комментарии?
java
timer
time-precision
mmcdole
источник
источник
nanoTime
обычно значительно точнее, чем currentTimeMillis, но это и относительно дорогой вызов.currentTimeMillis()
работает в нескольких (5-6) процессорных часах, nanoTime зависит от базовой архитектуры и может быть более 100 тактовых процессоров.System.currentTimeMillis()
: pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.htmlОтветы:
Если вам нужны исключительно точные измерения прошедшего времени , используйте
System.nanoTime()
.System.currentTimeMillis()
даст вам наиболее точное возможное время, прошедшее с начала эпохи в миллисекундах, ноSystem.nanoTime()
даст вам время с точностью до наносекунды относительно некоторой произвольной точки.Из документации Java:
Например, чтобы измерить, сколько времени занимает выполнение кода:
См. Также: JavaDoc System.nanoTime () и JavaDoc System.currentTimeMillis () для получения дополнительной информации.
источник
currentTimeMillis
измениться из-за перехода на летнее время? Переключатель DST не меняет количество секунд после эпохи. Это могут быть «настенные часы», но они основаны на UTC. Вы должны определить, основываясь на вашем часовом поясе и настройках летнего времени, что это означает для вашего местного времени (или использовать другие утилиты Java, чтобы сделать это для вас).Так как никто другой не упомянул об этом ...
Не безопасно сравнивать результаты
System.nanoTime()
звонков между разными потоками. Даже если события потоков происходят в предсказуемом порядке, разница в наносекундах может быть положительной или отрицательной.System.currentTimeMillis()
безопасен для использования между потоками.источник
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()
говорит: один и тот же источник используется всеми вызовами этого метода в экземпляре виртуальной машины Java; другие экземпляры виртуальной машины могут использовать другое происхождение. что означает , что он действительно возвращает то же самое через потоки.Обновление от Аркадия : Я наблюдал более правильное поведение в
System.currentTimeMillis()
Windows 7 в Oracle Java 8. Время было возвращено с точностью до 1 миллисекунды. Исходный код в OpenJDK не изменился, поэтому я не знаю, что вызывает лучшее поведение.Пару лет назад Дэвид Холмс из Sun опубликовал статью в блоге, в которой очень подробно рассматриваются API синхронизации Java (в частности,
System.currentTimeMillis()
иSystem.nanoTime()
), когда вы захотите использовать какие и как они работают внутри.Внутри Hotspot VM: часы, таймеры и планирование событий - Часть I - Windows
Один очень интересный аспект таймера, используемого Java в Windows для API, которые имеют параметр ожидания по времени, заключается в том, что разрешение таймера может изменяться в зависимости от того, какие другие вызовы API могли быть выполнены - в масштабе всей системы (не только в конкретном процессе) , Он показывает пример, где использование
Thread.sleep()
приведет к изменению этого разрешения.источник
GetSystemTimeAsFileTime
работало в XP против 7. Смотрите здесь для более подробной информации (tl; д-р он стал более точным, так как вся система ввела некоторые более точные методы синхронизации).System.nanoTime()
не поддерживается в старых JVM. Если это проблема, придерживайтесьcurrentTimeMillis
Что касается точности, вы почти правы. На некоторых компьютерах с Windows
currentTimeMillis()
имеет разрешение около 10 мс (не 50 мс). Я не уверен, почему, но некоторые машины Windows так же точны, как машины Linux.Я использовал GAGETimer в прошлом с умеренным успехом.
источник
Как уже говорили другие, currentTimeMillis - это время на часах, которое изменяется из-за перехода на летнее время, пользователей, меняющих настройки времени, високосных секунд и синхронизации времени в Интернете. Если ваше приложение зависит от монотонно увеличивающихся значений прошедшего времени, вы можете предпочесть nanoTime.
Вы можете подумать, что игроки не будут играть с настройками времени во время игры, и, возможно, вы будете правы. Но не стоит недооценивать сбои из-за синхронизации времени в Интернете или, возможно, пользователей удаленного рабочего стола. API nanoTime невосприимчив к таким нарушениям.
Если вы хотите использовать время на часах, но избегаете разрывов из-за синхронизации времени в Интернете, вы можете рассмотреть NTP-клиента, такого как Meinberg, который «настраивает» тактовую частоту на ноль, а не просто периодически сбрасывает часы.
Я говорю из личного опыта. В приложении для погоды, которое я разработал, я получал случайные всплески скорости ветра. Мне потребовалось некоторое время, чтобы понять, что моя временная база нарушается из-за поведения часов на типичном ПК. Все мои проблемы исчезли, когда я начал использовать nanoTime. Согласованность (монотонность) была важнее для моего приложения, чем грубая точность или абсолютная точность.
источник
System.currentTimeMillis()
сообщает прошедшее время (в миллисекундах) с начала эпохи Unix / Posix, которая наступила в полночь 1 января 1970 года по Гринвичу. Поскольку UTC никогда не корректируется для перехода на летнее время, это значение не будет смещено, когда местные часовые пояса добавляются или смещаются к местному времени для перехода на летнее время. Кроме того, Java Time Scale сглаживает високосные секунды, так что дни продолжают казаться 86 400 секунд.Да, если требуется такая точность, используйте
System.nanoTime()
, но имейте в виду, что вам требуется Java 5+ JVM.В моих системах XP, я вижу системное время, сообщаемое по крайней мере
100 микросекунд278 наносекунд, используя следующий код:источник
Для игровой графики и плавного обновления позиций используйте
System.nanoTime()
вместоSystem.currentTimeMillis()
. Я переключился с currentTimeMillis () на nanoTime () в игре и получил значительное визуальное улучшение плавности движений.Хотя одна миллисекунда может показаться, что она уже должна быть точной, визуально это не так. Факторы, которые
nanoTime()
можно улучшить, включают в себя:Как показывают другие ответы, nanoTime имеет затраты производительности при повторном вызове - лучше всего вызывать его только один раз за кадр и использовать одно и то же значение для вычисления всего кадра.
источник
У меня был хороший опыт работы с nanotime . Он обеспечивает время настенных часов в виде двух длинных (секунды с начала эпохи и наносекунды в течение этой секунды) с использованием библиотеки JNI. Он доступен с предварительно скомпилированной частью JNI для Windows и Linux.
источник
System.currentTimeMillis()
не является безопасным для истекшего времени, потому что этот метод чувствителен к системным изменениям часов реального времени системы. Вы должны использоватьSystem.nanoTime
. Пожалуйста, обратитесь к справке Java System:О методе nanoTime:
Если вы используете
System.currentTimeMillis()
ваше прошедшее время может быть отрицательным (Назад <- в будущее)источник
Одна вещь здесь - несоответствие метода nanoTime. Это не дает очень последовательные значения для того же самого input.currentTimeMillis делает намного лучше с точки зрения производительности и последовательности, и также, хотя и не столь точно, как nanoTime, имеет более низкий предел погрешности и, следовательно, больше точности в его значении. поэтому я бы предложил вам использовать currentTimeMillis
источник