Как задокументировано в блоге Beware для System.nanoTime () в Java , в системах x86 Java System.nanoTime () возвращает значение времени с помощью счетчика, специфичного для процессора . Теперь рассмотрим следующий случай, который я использую для измерения времени звонка:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
Теперь в многоядерной системе может быть так, что после измерения времени1 поток назначается другому процессору, чей счетчик меньше, чем у предыдущего процессора. Таким образом, мы можем получить значение в time2, которое меньше, чем time1. Таким образом, мы получили бы отрицательное значение в timeSpent.
Рассматривая этот случай, не правда ли, что System.nanotime пока бесполезен?
Я знаю, что изменение системного времени не влияет на nanotime. Это не проблема, которую я описал выше. Проблема в том, что каждый ЦП будет держать свой счетчик, так как он был включен. Этот счетчик может быть ниже на втором процессоре по сравнению с первым процессором. Поскольку поток может быть запланирован ОС на второй ЦП после получения time1, значение timeSpent может быть неправильным и даже отрицательным.
Ответы:
Этот ответ был написан в 2011 году с точки зрения того, что на самом деле делал Sun JDK того времени, работающего на операционных системах того времени. Это было давным-давно! Ответ Левентова предлагает более современную перспективу.
Это сообщение неверно и
nanoTime
безопасно. Есть комментарий к сообщению, которое ссылается на сообщение в блоге Дэвида Холмса , парня из Sun, работающего в режиме реального времени. Это говорит:Итак, в Windows это было проблемой до WinXP SP2, но не сейчас.
Я не могу найти часть II (или более), в которой говорится о других платформах, но в этой статье есть замечание, что Linux столкнулся и решил ту же проблему аналогичным образом, со ссылкой на FAQ для clock_gettime (CLOCK_REALTIME) , который говорит:
Итак, если ссылка Холмса может быть прочитана как подразумевающая эти
nanoTime
вызовыclock_gettime(CLOCK_REALTIME)
, то она безопасна с ядра 2.6.18 на x86 и всегда на PowerPC (потому что IBM и Motorola, в отличие от Intel, фактически знают, как проектировать микропроцессоры).К сожалению, нет никаких упоминаний о SPARC или Solaris. И, конечно, мы понятия не имеем, что делают JVM IBM. Но Sun JVM на современных Windows и Linux понимают это правильно.
РЕДАКТИРОВАТЬ: Этот ответ основан на источниках, которые он цитирует. Но я все еще волнуюсь, что это может быть совершенно неправильно. Еще одна актуальная информация была бы действительно ценной. Я только что натолкнулся на ссылку на четырехлетнюю новую статью о часах Linux, которая может быть полезна.
источник
void foo() { Thread.sleep(40); }
я получил отрицательное время (-380 мс!) С использованием одногоAthlon 64 X2 4200+
процессораЯ немного искал и обнаружил, что если человек педантичен, то да, это может считаться бесполезным ... в определенных ситуациях ... это зависит от того, насколько чувствительны ваши требования к времени ...
Проверьте эту цитату с сайта Java Sun:
У Java также есть предостережение для метода nanoTime () :
Казалось бы, единственный вывод, который можно сделать, состоит в том, что на nanoTime () нельзя полагаться как на точное значение. Таким образом, если вам не нужно измерять время, которое составляет всего лишь наносекунды, этот метод достаточно хорош, даже если полученное возвращаемое значение отрицательное. Однако, если вам нужна более высокая точность, они рекомендуют вам использовать JAVA RTS.
Таким образом, чтобы ответить на ваш вопрос ... никакой nanoTime () не бесполезен .... это просто не самый разумный метод для использования в любой ситуации.
источник
-100
,-99
,-98
(Очевидно , гораздо большие значения на практике). Они движутся в правильном направлении (увеличиваются), поэтому здесь нет проблем.Не нужно спорить, просто используйте источник. Вот, SE 6 для Linux, сделайте свои собственные выводы:
источник
Начиная с Java 7
System.nanoTime()
гарантируется безопасность по спецификации JDK.System.nanoTime()
Javadoc дает понять, что все наблюдаемые вызовы в JVM (то есть во всех потоках) являются монотонными:Реализация JVM / JDK отвечает за устранение несоответствий, которые могут наблюдаться при вызове базовых утилит ОС (например, упомянутых в ответе Тома Андерсона ).
Большинство других старых ответов на этот вопрос (написано в 2009–2012 гг.) Выражают FUD, который, вероятно, имел отношение к Java 5 или Java 6, но больше не относится к современным версиям Java.
Однако следует отметить, что, несмотря на гарантии
nanoTime()
безопасности JDK, в OpenJDK было несколько ошибок, из-за которых он не поддерживал эту гарантию на определенных платформах или при определенных обстоятельствах (например, JDK-8040140 , JDK-8184271 ). НаnanoTime()
данный момент в OpenJDK нет открытых (известных) ошибок , но обнаружение новой такой ошибки или регрессия в новой версии OpenJDK никого не должно шокировать.Имея это в виду, код, который использует
nanoTime()
временную блокировку, интервальное ожидание, тайм-ауты и т. Д., Предпочтительно должен рассматривать отрицательные временные разницы (тайм-ауты) как нули, а не как исключения. Эта практика также является предпочтительной , поскольку он согласуется с поведением всех синхронизированных методов ожидания во всех классах вjava.util.concurrent.*
, напримерSemaphore.tryAcquire()
,Lock.tryLock()
,BlockingQueue.poll()
и т.д.Тем не менее,
nanoTime()
все же следует отдать предпочтение реализации временных блокировок, интервалов ожидания, тайм-аутов и т. Д.,currentTimeMillis()
Поскольку последний подвержен явлению «время идет назад» (например, из-за коррекции времени сервера), тоcurrentTimeMillis()
есть не подходит для измерения временных интервалов. вообще. Смотрите этот ответ для получения дополнительной информации.Вместо
nanoTime()
непосредственного использования для измерения времени выполнения кода, предпочтительно использовать специализированные эталонные тестовые среды и профилировщики, например, JMH и асинхронный профилировщик в режиме профилирования настенных часов .источник
Отказ от ответственности: я разработчик этой библиотеки
Вам может понравиться это лучше:
http://juliusdavies.ca/nanotime/
Но он копирует файл DLL или Unix .so (общий объект) в домашний каталог текущего пользователя, чтобы он мог вызывать JNI.
Некоторая справочная информация находится на моем сайте по адресу:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
источник
Linux исправляет расхождения между процессорами, а Windows - нет. Я полагаю, вы предполагаете, что System.nanoTime () является точным только с точностью до 1 микросекунды. Простой способ увеличить время - это вызвать foo () 1000 или более раз и разделить время на 1000.
источник
Абсолютно не бесполезно. Поклонники синхронизации правильно указывают на проблему с многоядерностью, но в приложениях с реальными словами это часто радикально лучше, чем currentTimeMillis ().
При вычислении графических позиций в обновлениях кадров nanoTime () приводит к НАМНОГО более плавному движению в моей программе.
И я тестирую только на многоядерных машинах.
источник
Я видел отрицательное прошедшее время, сообщенное при использовании System.nanoTime (). Чтобы быть ясным, рассматриваемый код:
и переменная 'elapsedNanos' имела отрицательное значение. (Я уверен, что промежуточный вызов также занял менее 293 лет, что является точкой переполнения для наноса, хранящегося в longs :)
Это произошло при использовании IBM v1.5 JRE 64bit на оборудовании IBM P690 (многоядерный), работающем под управлением AIX. Я видел эту ошибку только один раз, поэтому она встречается крайне редко. Я не знаю причину - это аппаратная проблема, дефект JVM - я не знаю. Я также не знаю последствия для точности nanoTime () в целом.
Чтобы ответить на первоначальный вопрос, я не думаю, что nanoTime бесполезен - он обеспечивает синхронизацию менее миллисекунды, но существует реальный (не только теоретический) риск того, что он будет неточным, что вам необходимо учитывать.
источник
Это не проблема для Core 2 Duo под управлением Windows XP и JRE 1.5.0_06.
В тесте с тремя потоками я не вижу System.nanoTime (), идущий в обратном направлении. Процессоры оба заняты, и потоки иногда засыпают, чтобы провоцировать перемещение потоков.
[EDIT] Я бы предположил, что это происходит только на физически отдельных процессорах, то есть что счетчики синхронизируются для нескольких ядер на одном кристалле.
источник
Нет, это не так ... Это зависит только от вашего процессора, проверьте High Precision Event Timer, чтобы узнать, как / почему вещи обрабатываются по-разному в зависимости от процессора.
По сути, прочитайте исходный код Java и проверьте, что ваша версия делает с функцией, и если она работает с процессором, вы будете на ней работать.
IBM даже предлагает использовать его для сравнительного анализа производительности (публикация 2008 г., но обновленная).
источник
Я ссылаюсь на то, что по сути является тем же обсуждением, где Питер Лори дает хороший ответ. Почему я получаю отрицательное прошедшее время, используя System.nanoTime ()?
Многие люди упоминали, что в Java System.nanoTime () может возвращать отрицательное время. Я прошу прощения за повторение того, что уже сказали другие люди.
Было бы здорово, если бы System.nanoTime () возвращал coreID там, где он выполнялся.
источник
Java является кроссплатформенной, а nanoTime зависит от платформы. Если вы используете Java - когда не используйте nanoTime. Я нашел реальные ошибки в различных реализациях jvm с этой функцией.
источник
Документация Java 5 также рекомендует использовать этот метод для той же цели.
Java 5 API Doc
источник
Кроме того,
System.currentTimeMillies()
меняется, когда вы меняете системные часы, аSystem.nanoTime()
не изменяет , поэтому последний безопаснее измерять длительности.источник
nanoTime
крайне небезопасно для времени. Я опробовал его на моих основных алгоритмах тестирования простоты, и он дал ответы, которые были буквально на расстоянии одной секунды для одного и того же ввода. Не используйте этот нелепый метод. Мне нужно что-то более точное и точное, чем получить время Миллис, но не так плохо, какnanoTime
.источник