Измерение накладных расходов на время в Java
Когда я измеряю затраченное время на низком уровне, у меня есть выбор использовать один из следующих методов:
System.currentTimeMillis();
System.nanoTime();
Оба метода реализованы native
. Прежде чем углубляться в какой-либо код на C, есть ли у кого-то информация о том, есть ли значительная задержка при вызове одного из них? Я имею в виду, если мне неважна дополнительная точность, какой из них можно ожидать, что будет менее затратным по времени CPU?
Примечание: Я использую стандартный JDK Java 1.6, но вопрос может быть актуален для любой JRE...
5 ответ(ов)
На теоретическом уровне, для виртуальной машины (VM), которая использует родные потоки и работает на современном прерываемом операционной системе, метод currentTimeMillis может быть реализован так, чтобы выполняться только один раз за тайм-срез. Предположительно, реализации метода nanoTime не будут жертвовать точностью.
Если у вас есть дополнительные вопросы по поводу реализации или необходимости в более детальных примерах, не стесняйтесь задавать их!
Не думаю, что вам стоит беспокоиться о накладных расходах на оба метода. Они настолько малы, что их едва ли можно измерить. Вот быстрый микро-бенчмарк для обоих:
for (int j = 0; j < 5; j++) {
long time = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
long x = System.currentTimeMillis();
}
System.out.println((System.nanoTime() - time) + "нс на миллион");
time = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
long x = System.nanoTime();
}
System.out.println((System.nanoTime() - time) + "нс на миллион");
System.out.println();
}
И последние результаты:
14297079нс на миллион
29206842нс на миллион
Действительно, System.currentTimeMillis()
кажется в два раза быстрее, чем System.nanoTime()
. Однако 29нс — это гораздо меньше, чем что-либо другое, что вы будете измерять. Я бы рекомендовал использовать System.nanoTime()
для большей точности и достоверности, так как он не связан с часами.
Вы всегда должны использовать System.nanoTime()
для измерения времени выполнения. Дело не только в наносекундной точности; System.currentTimeMillis()
возвращает "реальное время", в то время как System.nanoTime()
предназначен для замеров времени и не имеет тех "проблем с реальным временем", которые есть у другого метода. Из документации Javadoc к System.nanoTime()
:
Этот метод можно использовать только для измерения прошедшего времени и он не связан с какой-либо другой концепцией системного или настенных часов.
System.currentTimeMillis()
обычно работает очень быстро (по моим данным, около 5-6 циклов ЦП, но не помню, где это читал), однако его разрешение может различаться на разных платформах.
Если вам нужна высокая точность, используйте nanoTime()
. Если вас беспокоит накладные расходы, лучше выбрать currentTimeMillis()
.
Проблема с использованием currentTimeMillis()
заключается в том, что когда ваша виртуальная машина (VM) корректирует время (это обычно происходит автоматически), currentTimeMillis()
будет следовать за этими изменениями. В результате вы получите неточные значения, что может оказаться особенно критичным при проведении бенчмаркинга. Для более точного измерения времени стоит рассмотреть использование System.nanoTime()
, который не подвержен таким корректировкам и лучше подходит для измерений временных интервалов.
Java: накладные расходы if vs. try/catch
Что значит 'synchronized'?
Почему нет ConcurrentHashSet, если есть ConcurrentHashMap?
Как объявить массив в одну строку?
Какие проблемы следует учитывать при переопределении equals и hashCode в Java?