Вопрос

Точность против.Точность

Я хотел бы знать, следует ли мне использовать System.currentTimeMillis() или Система.nanoTime() при обновлении позиций моего объекта в игре?Изменение их движения прямо пропорционально времени, прошедшему с момента последнего звонка, и я хочу быть максимально точным.

Я читал, что между различными операционными системами существуют серьезные проблемы с временным разрешением (а именно, что Mac / Linux имеют разрешение почти 1 мс, а Windows — 50 мс??).Я в основном запускаю свои приложения в Windows, и разрешение 50 мс кажется довольно неточным.

Есть ли варианты лучше, чем те два, которые я перечислил?

Есть предложения/комментарии?

Это было полезно?

Решение

Если вы просто ищете чрезвычайно точные измерения пройденное время, использовать System.nanoTime(). System.currentTimeMillis() даст вам наиболее точное время, прошедшее с начала эпохи, в миллисекундах, но System.nanoTime() дает вам время с точностью до наносекунды относительно некоторой произвольной точки.

Из документации Java:

public static long nanoTime()

Возвращает текущее значение наиболее точного доступного системного таймера в наносекундах.

Этот метод может использоваться только для измерения истекающего времени и не связан с каким-либо другим понятием системы или времени на стену.Возвращенное значение представляет наносекунд с некоторого фиксированного, но произвольного времени (возможно, в будущем, поэтому значения могут быть отрицательными).Этот метод обеспечивает наносекундную точность, но не обязательно наносекундную точность.Никаких гарантий о том, как часто изменяются значения.Различия в последовательных звонках, которые охватывают более примерно 292 года (263Наносекунд) не будут точно рассчитывать истешенное время из -за численного переполнения.

Например, чтобы измерить, сколько времени занимает выполнение некоторого кода:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

Смотрите также: JavaDoc System.nanoTime() и JavaDoc System.currentTimeMillis() для получения дополнительной информации.

Другие советы

Поскольку больше никто об этом не упомянул…

Небезопасно сравнивать результаты System.nanoTime() вызовы между разными потоками.Даже если события потоков происходят в предсказуемом порядке, разница в наносекундах может быть положительной или отрицательной.

System.currentTimeMillis() безопасен для использования между потоками.

Обновить по Аркадий:Я заметил более правильное поведение System.currentTimeMillis() в Windows 7 в Oracle Java 8.Время было возвращено с точностью до 1 миллисекунды.Исходный код OpenJDK не изменился, поэтому я не знаю, что является причиной лучшего поведения.


Дэвид Холмс из Sun пару лет назад опубликовал в блоге статью, в которой очень подробно рассматриваются API-интерфейсы синхронизации Java (в частности, System.currentTimeMillis() и System.nanoTime()), когда вы захотите их использовать и как они работают внутри.

Внутри виртуальной машины Hotspot:Часы, таймеры и планирование событий. Часть I. Windows.

Одним из очень интересных аспектов таймера, используемого Java в Windows для API, имеющих параметр ожидания по времени, является то, что разрешение таймера может меняться в зависимости от того, какие другие вызовы API могли быть сделаны - в масштабе всей системы (а не только в конкретном процессе). .Он показывает пример использования Thread.sleep() приведет к изменению разрешения.

System.nanoTime() не поддерживается в старых JVM.Если это вас беспокоит, придерживайтесь currentTimeMillis

Насчет точности вы почти правы.На НЕКОТОРЫХ компьютерах с Windows currentTimeMillis() имеет разрешение около 10 мс (а не 50 мс).Я не знаю почему, но некоторые машины с Windows столь же точны, как и машины с Linux.

я использовал GAGEТаймер в прошлом с умеренным успехом.

Как уже говорили другие, currentTimeMillis — это время часов, которое меняется из-за перехода на летнее время, изменения пользователями настроек времени, дополнительных секунд и синхронизации времени в Интернете.Если ваше приложение зависит от монотонного увеличения значений прошедшего времени, вместо этого вы можете предпочесть nanoTime.

Вы можете подумать, что игроки не будут менять настройки времени во время игры, и, возможно, вы будете правы.Но не стоит недооценивать сбои из-за синхронизации времени в Интернете или, возможно, из-за пользователей удаленного рабочего стола.API nanoTime невосприимчив к такого рода сбоям.

Если вы хотите использовать время на часах, но избежать разрывов из-за синхронизации времени в Интернете, вы можете рассмотреть возможность использования NTP-клиента, такого как Meinberg, который «настраивает» тактовую частоту для ее обнуления, а не просто периодически сбрасывает часы.

Я говорю из личного опыта.В погодном приложении, которое я разработал, я получал случайные скачки скорости ветра.Мне потребовалось некоторое время, чтобы осознать, что моя временная шкала была нарушена поведением часов на типичном ПК.Все мои проблемы исчезли, когда я начал использовать nanoTime.Последовательность (монотонность) была более важна для моего приложения, чем грубая точность или абсолютная точность.

Да, если требуется такая точность, используйте System.nanoTime(), но имейте в виду, что в этом случае вам потребуется JVM Java 5+.

В моих системах XP я вижу, что системное время сообщается как минимум 100 микросекунд 278 наносекунды используя следующий код:

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }

у меня был хороший опыт работы с нановремя.Он предоставляет время настенных часов в виде двух длинных значений (секунд с начала эпохи и наносекунд в пределах этой секунды), используя библиотеку JNI.Он доступен с частью JNI, предварительно скомпилированной как для Windows, так и для Linux.

Для игровой графики и плавного обновления позиций используйте System.nanoTime() скорее, чем System.currentTimeMillis().Я переключился с currentTimeMillis() на nanoTime() в игре и получил значительное визуальное улучшение плавности движения.

Хотя может показаться, что одна миллисекунда уже должна быть точной, визуально это не так.Факторы nanoTime() можно улучшить, включая:

  • точное позиционирование пикселей ниже разрешения настенных часов
  • возможность сглаживания между пикселями, если хотите
  • Погрешность настенных часов Windows
  • дрожание часов (непостоянство того, когда настенные часы действительно тикают вперед)

Как показывают другие ответы, nanoTime действительно снижает производительность при многократном вызове - было бы лучше вызывать его только один раз для каждого кадра и использовать одно и то же значение для расчета всего кадра.

System.currentTimeMillis() небезопасен для затраченного времени, поскольку этот метод чувствителен к изменениям системных часов реального времени.Вы должны использовать System.nanoTime.Пожалуйста, обратитесь к справке системы Java:

О методе nanoTime:

..Этот метод обеспечивает наносекундную точность, но не обязательно наносекундное разрешение (то есть, как часто изменяется значение) - никаких гарантий не производится, за исключением того, что разрешение, по крайней мере, так же хорошо, как и у CurrentTimeMiLIS () ..

Если вы используете System.currentTimeMillis() прошедшее время может быть отрицательным (Назад <- в будущее)

одна вещь здесь - это непоследовательность метода nanoTime. он не дает очень последовательных значений для одного и того же ввода. CurrentTimeMillis работает намного лучше с точки зрения производительности и согласованности, а также, хотя и не так точен, как nanoTime, имеет меньшую погрешность. , и, следовательно, более точное определение его значения.поэтому я бы посоветовал вам использовать currentTimeMillis

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top