Подтвердить что ты не робот

Почему System.nanoTime() медленнее (по производительности), чем System.currentTimeMillis()?

Сегодня я сделал небольшой быстрый тест, чтобы проверить скорость работы System.nanoTime() и System.currentTimeMillis():

long startTime = System.nanoTime();

for(int i = 0; i < 1000000; i++) {
  long test = System.nanoTime();
}

long endTime = System.nanoTime();

System.out.println("Total time: "+(endTime-startTime));

Вот результаты:

System.currentTimeMillis(): average of 12.7836022 / function call
System.nanoTime():          average of 34.6395674 / function call

Почему разница в скорости работы такая большая?

Контрольная система:

Java 1.7.0_25
Windows 8 64-bit
CPU: AMD FX-6100
4b9b3361

Ответ 1

Из этого блога Oracle:

System.currentTimeMillis() реализуется с использованием GetSystemTimeAsFileTime, который, по сути, просто читает низкую которое поддерживает Windows. Чтение этого глобальная переменная, естественно, очень быстрая - около 6 циклов в соответствии с сообщила информация.

System.nanoTime() реализуется с использованием QueryPerformanceCounter/ QueryPerformanceFrequency API (если доступно, иначе он возвращает currentTimeMillis*10^6). QueryPerformanceCounter(QPC) реализуется по-разному в зависимости от используемого оборудования. Обычно он будет использовать либо программируемый интервал-таймер (PIT), либо мощность ACPI таймер управления (PMT) или счетчик времени метки CPU (TSC). Доступ к PIT/PMT требует выполнения инструкций порта медленного ввода-вывода и в результате время выполнения для QPC находится в порядке микросекунд. Напротив, чтение TSC составляет порядка 100 часов циклов (чтобы прочитать TSC от чипа и преобразовать его в значение времени на основе рабочей частоты).

Возможно, этот ответ на вопрос. Эти два метода используют различное количество тактовых циклов, что приводит к медленной скорости более поздней.

Далее в этом блоге в разделе заключения:

Если вы заинтересованы в измерении/вычислении прошедшего времени, всегда используйте System.nanoTime(). В большинстве систем это даст разрешение порядка микросекунд. Имейте в виду, что этот вызов может также занять микросекунды для выполнения на некоторых платформах.

Ответ 2

В большинстве ОС (вы не указали, какой из них вы используете) есть счетчик/часы памяти, который обеспечивает миллисекундную точность (или близко к ней). Для точности наносекунды большинству приходится читать аппаратный счетчик. Коммуникация с оборудованием медленнее, чем чтение некоторого значения уже в памяти.

Ответ 3

Это может быть только в Windows. См. этот ответ по аналогичному вопросу.

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

Ответ 4

Вы измеряете это на Windows, не так ли. Я прошел это упражнение в 2008 году. NanoTime IS медленнее в Windows, чем currentTimeMillis. Насколько я помню, на Linux нанотим работает быстрее, чем currentTimeMillis, и, безусловно, быстрее, чем в Windows.

Важно отметить, что если вы пытаетесь измерить совокупность нескольких субмиллисекундных операций, вы должны использовать nanotime, как если бы операция закончилась менее чем на 1 000 секунд секунды вашего кода, сравнивая currentTimeMillis, как мгновенно, поэтому 1000 из них все равно будут мгновенными. То, что вы, возможно, захотите сделать, это использовать нанотиму, затем округлую до ближайшей миллисекунды, поэтому, если операция заняла 8000 наносекунд, она будет считаться 1 миллисекундой, а не 0.

Ответ 5

Что вы можете сделать, так это использовать нанотим, затем округлить до ближайшей миллисекунды, поэтому, если операция заняла 8000 наносекунд, она будет считаться 1 миллисекундой, а не 0.

Арифметическое примечание:

8000 наносекунд - 8 микросекунд, составляет 0,008 миллисекунды. Округление займет до 0 миллисекунд.