Измерение времени в Java - PullRequest
45 голосов
/ 12 апреля 2011

При измерении прошедшего времени на низком уровне у меня есть выбор использования любого из них:

System.currentTimeMillis();
System.nanoTime();

Оба метода реализованы native.Прежде чем копаться в каком-либо C-коде, кто-нибудь знает, есть ли существенные накладные расходы, вызывающие один или другой?Я имею в виду, если меня не волнует дополнительная точность, какая из них может занять меньше процессорного времени?

Примечание: я использую стандарт Java 1.6 JDK, но вопрос может бытьдействителен для любого JRE ...

Ответы [ 7 ]

43 голосов
/ 10 марта 2014

Ответ, помеченный правильно на этой странице, на самом деле не верен.Это недопустимый способ написания эталонного теста из-за устранения мертвого кода JVM (DCE), замены в стеке (OSR), развертывания цикла и т. Д. Только инфраструктура, подобная инфраструктуре микробанчмаркинга Oracle JMH, может правильно измерить нечто подобное.Прочитайте этот пост , если у вас есть какие-либо сомнения относительно достоверности таких микро-тестов.

Вот тест JMH для System.currentTimeMillis() против System.nanoTime():

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class NanoBench {
   @Benchmark
   public long currentTimeMillis() {
      return System.currentTimeMillis();
   }

   @Benchmark
   public long nanoTime() {
    return System.nanoTime();
   }
}

И вот результаты (на Intel Core i5):

Benchmark                            Mode  Samples      Mean   Mean err    Units
c.z.h.b.NanoBench.currentTimeMillis  avgt       16   122.976      1.748    ns/op
c.z.h.b.NanoBench.nanoTime           avgt       16   117.948      3.075    ns/op

, который показывает, что System.nanoTime() немного быстрее: ~ 118 нс за вызов по сравнению с ~ 123 нс.Тем не менее, также ясно, что, если принять во внимание среднюю ошибку, между ними будет очень мало различий.Результаты также могут отличаться в зависимости от операционной системы.Но общий вывод должен состоять в том, что они по существу эквивалентны с точки зрения накладных расходов.

ОБНОВЛЕНИЕ 2015/08/25: Хотя этот ответ ближе к исправлению этого большинства, используя JMH для измерения, он все еще не верен.Измерение чего-то вроде System.nanoTime() само по себе является особым видом искаженного бенчмаркинга.Ответ и окончательная статья здесь .

25 голосов
/ 12 апреля 2011

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

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) + "ns per million");

    time = System.nanoTime();
    for (int i = 0; i < 1000000; i++) {
        long x = System.nanoTime();
    }
    System.out.println((System.nanoTime() - time) + "ns per million");

    System.out.println();
}

И последний результат:

14297079ns per million
29206842ns per million

Кажется, что System.currentTimeMillis() в два раза быстрее System.nanoTime().Однако 29 нс будет намного короче, чем все, что вы бы измеряли в любом случае.Я бы пошел на System.nanoTime() за точность и аккуратность, поскольку это не связано с часами.

11 голосов
/ 12 апреля 2011

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

Этот метод может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системного или настенного времени.

6 голосов
/ 13 апреля 2011

Если у вас есть время, посмотрите этот разговор Клиффа Клика , он говорит о цене System.currentTimeMillis, а также о других вещах.

6 голосов
/ 12 апреля 2011

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

Так что, если вам нужна высокая точность, переходите на nanoTime(), если вас беспокоит накладные расходы, переходите на currentTimeMillis().

4 голосов
/ 20 ноября 2016

Принятый ответ на этот вопрос действительно неверен. Альтернативный ответ, предоставленный @brettw, хорош, но, тем не менее, освещает детали.

Для полной обработки этого предмета и реальной стоимости этих звонков, пожалуйста, см. https://shipilev.net/blog/2014/nanotrusting-nanotime/

Чтобы ответить на заданный вопрос:

Кто-нибудь знает, есть ли существенные накладные расходы на вызов одного или другого?

  • Затраты на вызов System#nanoTime составляют от 15 до 30 наносекунд на вызов.
  • Значение, сообщаемое nanoTime, его разрешение изменяется только один раз за 30 наносекунд

Это означает, что в зависимости от того, пытаетесь ли вы сделать миллион запросов в секунду, вызов nanoTime означает, что вы фактически теряете огромную часть второго вызова nanoTime. Для таких случаев использования рассмотрите возможность измерения запросов со стороны клиента, что гарантирует, что вы не попадете в скоординированное упущение , измерение глубины очереди также является хорошим индикатором.

Если вы не пытаетесь втиснуть столько работы, сколько сможете в одну секунду, тогда nanoTime не будет иметь большого значения, но согласованное упущение все еще является фактором.

Наконец, для полноты, currentTimeMillis не может использоваться независимо от его стоимости. Это потому, что не гарантируется перемещение вперед между двумя вызовами. Особенно на сервере с NTP currentTimeMillis постоянно движется. Не говоря уже о том, что большинство измерений компьютера не занимают миллисекунды.

2 голосов
/ 12 апреля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...