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

Каково текущее состояние дел в мире Java-таймеров?

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

Я не тестировал тесты, так как я реалистично отношусь к моей способности проводить эксперимент в отношении такого чувствительного вопроса, но мои условия действительно четко определены, поэтому я жду довольно простого ответа.

Итак, в среднем 64-разрядный Linux (подразумевающий 64-разрядную JRE), Java 8 и современное оборудование, переключится на nanoTime(), стоимость меня на микросекунды, чтобы позвонить? Должен ли я оставаться с currentTimeMillis()?

4b9b3361

Ответ 1

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

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

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

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

Обновление: Существует одно место, где мы используем currentTimeMillis как проверку работоспособности при подключении двух хостов, но мы проверяем, находятся ли часы хостов более чем на 5 минут.

Ответ 2

Если вы используете currentTimeMillis() и довольны разрешением, то вы определенно не должны меняться.

В соответствии с javadoc:

Этот метод обеспечивает наносекундную точность, но не обязательно   наносекундное разрешение (то есть, как часто изменяется значение)   никакие гарантии не принимаются, за исключением того, что резолюция по крайней мере как   как {@link #currentTimeMillis()}.

Таким образом, в зависимости от реализации ОС нет гарантии, что возвращаемое нано-время было бы правильным! Это всего лишь 9 цифр и имеет такое же количество миллисекунд, что и currentTimeMillis().

Совершенно допустимая реализация может быть currentTimeMillis() * 1000000

Поэтому я не думаю, что вы действительно получаете выгоду от nano секунд, даже если не было проблемы с производительностью.

Ответ 3

Хочу подчеркнуть, что даже если вызовы будут очень дешевыми, вы не получите наносекундное разрешение ваших измерений.

Позвольте мне привести пример (код из http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#nanoTime--):

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

Таким образом, хотя обе длинные значения будут разрешены на наносекунду, JVM не дает вам гарантии, что каждый вызов, который вы делаете для nanoTime(), JVM даст вам новое значение.

Чтобы проиллюстрировать это, я написал простую программу и запустил ее на Win7x64 (не стесняйтесь запускать ее и сообщать о результатах):

package testNano;
public class Main {
    public static void main(String[] args) {
        long attempts = 10_000_000L;
        long stale = 0;
        long prevTime;
        for (int i = 0; i < attempts; i++) {
            prevTime = System.nanoTime();
            long nanoTime = System.nanoTime();
            if (prevTime == nanoTime) stale++;
        }
        System.out.format("nanoTime() returned stale value in %d out of %d tests%n", stale, attempts);
    }
}

Отпечатает nanoTime() returned stale value in 9117171 out of 10000000 tests.

ИЗМЕНИТЬ

Я также рекомендую прочитать статью Oracle по этому вопросу: https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks. Выводы статьи:

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

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

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

Ответ 4

Запуск этого очень простого теста:

public static void main(String[] args) {
    // Warmup loops
    long l;

    for (int i=0;i<1000000;i++) {
        l = System.currentTimeMillis();
    }

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

    // Full loops
    long start = System.nanoTime();
    for (int i=0;i<10000000;i++) {
        l = System.currentTimeMillis();
    }
    start = System.nanoTime()-start;
    System.err.println("System.currentTimeMillis() "+start/1000);

    start = System.nanoTime();
    for (int i=0;i<10000000;i++) {
        l = System.nanoTime();
    }
    start = System.nanoTime()-start;
    System.err.println("System.nanoTime() "+start/1000);

}

В Windows 7 это означает, что миллисы будут чуть более чем в 2 раза быстрее:

System.currentTimeMillis() 138615
System.nanoTime() 299575

На других платформах разница не такая большая, при этом nanoTime() на самом деле немного (~ 10%) быстрее:

В OS X:

System.currentTimeMillis() 463065
System.nanoTime() 432896

В Linux с OpenJDK:

System.currentTimeMillis() 352722
System.nanoTime() 312960

Ответ 5

Хорошо, что самое лучшее, что нужно делать в таких ситуациях, - всегда проверять его. И поскольку время зависит только от вашей платформы и ОС, мы действительно ничего не можем сделать для вас здесь, тем более, что вы нигде не объясняете , что, на самом деле вы используете таймер для.

Ни nanoTime, ни currentTimeMillis, как правило, не гарантируют монотонность (nanoTime делает только HotSpot для Solaris и в противном случае полагается на существующий монотонный источник времени для ОС, поэтому для большинства людей он будет монотонным, даже если currentTimeMillis не является).

К счастью для вас писать тесты на Java в наши дни относительно легко благодаря jmh (java мерной жгуту) и даже удачливее для вас Алексей Шипилов фактически исследовал nanoTime некоторое время назад: Смотрите здесь - включая исходный код, чтобы сделать интересный бенчмаркинг самостоятельно (это также хороший учебник для самого jmh, если вы хотите написать точные тесты с относительно небольшим знанием - вот что выбрать. просто удивительно, как далеко отстали инженеры от этого проекта, чтобы сделать бенчмаркинг как можно более простым для всего населения! Хотя вы, конечно, все равно можете испортить, если не будете осторожны; -))

Чтобы обобщить результаты для современного дистрибутива Linux или Solaris и процессора x86:

  • Точность: 30 нс
  • Задержка: наилучший вариант 30ns

Окна:

  • Точность: чрезвычайно переменная, от 370 до 15 мкс
  • Задержка: чрезвычайно переменная, от 15 до 15 мкс

Но обратите внимание, что Windows также известна, чтобы дать вам точность до 100 мс для currentTimeMillis в некоторых редких ситуациях soo.. заберите свой яд.

Mac OS X:

  • Точность: 1μs
  • Задержка: 50 нс

Быть разным, эти результаты будут сильно отличаться в зависимости от используемой платформы (CPU/MB - есть некоторые интересные старые аппаратные комбинации, хотя они, к счастью, становятся старше) и ОС. Похоже, что это просто работает на процессоре с частотой 800 МГц, ваши результаты будут отличаться по сравнению с сервером с частотой 3,6 ГГц.