Как определить время выполнения метода в Java?

  1. Как узнать время выполнения метода?
  2. Есть ли служебный класс Timer для таких вещей, как определение времени выполнения задачи и т. д.?

Большинство поисковых запросов в Google возвращают результаты для таймеров, которые планируют потоки и задачи, что мне не нужно.

Позже аналогичный Вопрос: Как написать правильный микротест на Java?

Basil Bourque 02.07.2016 01:48

JAMon API - это бесплатный, простой, высокопроизводительный, потокобезопасный Java API, который позволяет разработчикам легко контролировать производительность и масштабируемость производственных приложений. JAMon отслеживает совпадения, время выполнения (общее, среднее, минимальное, максимальное, стандартное отклонение) и многое другое. http://jamonapi.sourceforge.net/ скачать: http://sourceforge.net/project/showfiles.php?group_id=96550

Mike Pone 08.10.2008 01:47

Вы также можете посмотреть класс Секундомер Apache Commons Lang. Простой, но полезный служебный класс.

user101561 05.05.2009 17:10

Да, секундомер отлично подходит для этого.

Shubham Pandey 01.08.2019 09:08

Java 8 с использованием класса Instant: stackoverflow.com/a/30975902/1216775

akhil_mittal 01.08.2019 14:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
893
5
746 421
40
Перейти к ответу Данный вопрос помечен как решенный

Ответы 40

Вероятно, это не то, что вы хотели, чтобы я сказал, но это хорошее применение АОП. Оберните прокси-перехватчик вокруг своего метода и отсчитайте время.

К сожалению, вопрос о том, что, почему и как в АОП выходит за рамки этого ответа, но я бы сделал это именно так.

Обновлено: Вот ссылка до Spring AOP, чтобы вы начали, если вы заинтересованы. Это наиболее доступная реализация АОП, которую Iive встречал для java.

Кроме того, учитывая очень простые предложения всех остальных, я должен добавить, что АОП предназначен для случаев, когда вы не хотите, чтобы такие вещи, как время, вторгались в ваш код. Но во многих случаях такой простой и легкий подход подходит.

Вот руководство о том, как это сделать с помощью Spring: veerasundar.com/blog/2010/01/…

David Tinker 04.01.2011 14:05

Я согласен с простым ответом. Работает для меня.

long startTime = System.currentTimeMillis();

doReallyLongThing();

long endTime = System.currentTimeMillis();

System.out.println("That took " + (endTime - startTime) + " milliseconds");

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

Среднее значение за пару прогонов (чем больше, тем лучше), и вы получите неплохое представление.

На самом деле System.currentTimeMillis () точен только выше 15 мс. При действительно низких значениях этому нельзя доверять. Решением для этого (как уже упоминалось) является System.nanoTime ();

Steve g 08.10.2008 01:38

Хорошо, я собирался принять это как официальный ответ, пока не прочитал комментарий Стива Дж. Отличный лакомый кусочек, Стив!

Ogre Psalm33 08.10.2008 16:15

nanoTime () не гарантирует точность лучше, чем currentTimeMillis, но многие реализации JVM действительно имеют лучшую точность с nanoTime.

James Schek 08.10.2008 21:22

@JamesSchek Вам действительно нужно следить за своей формулировкой, как я уже упоминал в этом идентичном комментарии в другом месте; nanoTime гарантированно будет по крайней мере столь же решительный как currentTimeMillis. docs.oracle.com/javase/7/docs/api/java/lang/…

b1nary.atr0phy 18.05.2013 19:37

Одно небольшое преимущество currentTimeMillis заключается в том, что это фактическая временная метка, и ее можно также использовать для регистрации времени начала / окончания, в то время как nanoTime "может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системы или стены. время часов ".

Brad Parks 28.11.2016 17:17

Если ты хочешь настенные часы

long start_time = System.currentTimeMillis();
object.method();
long end_time = System.currentTimeMillis();
long execution_time = end_time - start_time;
Ответ принят как подходящий

Всегда есть старомодный способ:

long startTime = System.nanoTime();
methodToTime();
long endTime = System.nanoTime();

long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.

на самом деле, это "по-новому", потому что вы использовали nanoTime, который не был добавлен до java5

John Gardner 08.10.2008 02:26

Это (или использование System.currentTimeMillis ()) похоже на то, как это обычно делается в Java ... что я все равно видел. Меня все еще слегка удивляет, что нет удобного встроенного класса, такого как Timer t = new Timer (); Строка s = t.getElapsed (формат); так далее...

Ogre Psalm33 08.10.2008 16:48

nanoTime не гарантирует лучшей точности, чем currentTimeMillis (), хотя обычно это так. форумы.sun.com/thread.jspa?messageID=9460663 и simongbrown.com/blog/2007/08/20/…

James Schek 08.10.2008 21:20

Конечно, всегда важно помнить о подводных камнях микротестирования, таких как оптимизация компилятора / JVM, которая может исказить результат = 8-)

Yuval 07.01.2009 18:26

В блоке finally нет необходимости, так как endTime не будет использоваться при возникновении исключения.

Peter Lawrey 05.05.2009 23:42

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

James Scriven 25.05.2011 18:22

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

Java Spring Coder 26.03.2013 03:32

Хорошо, это хорошо. Но как ОБЪЕДИНИТЬ ТЕСТИРОВАНИЕ этого поведения? т.е. я хочу подтвердить, что метод возвращает время выполнения, которое является разницей между endTime и startTime.

Adelin 10.05.2013 15:08

@JamesSchek Будьте осторожны со своей формулировкой, nanoTime гарантированно будет по крайней мере столь же решительный как currentTimeMillis. docs.oracle.com/javase/7/docs/api/java/lang/…

b1nary.atr0phy 18.05.2013 19:33

@ OgrePsalm33 В Java 7 есть класс Timer, но он используется для планирования задач.

Chthonic Project 24.07.2013 22:25

@ChthonicProject Ну конечно. В моем примере имя класса было просто фиктивным представлением.

Ogre Psalm33 25.07.2013 16:47

Этот ответ не совсем правильный, проверьте мой ответ, если вы ищете время, затрачиваемое только на ваше приложение.

TondaCZE 06.04.2014 17:49

Пожалуйста, обратитесь к этому ответу stackoverflow.com/a/3383047/870547, чтобы сделать это на Java 8 способом

Kay Gee 05.12.2014 21:56

Это секундомер, который я сделал, он позволяет статически добавлять именованные таймеры. Его очень просто использовать, см. Класс DocBlock. gist.github.com/juanmf/4147a9b7010c7b04c003 вы хотите поместить его в свой пакет утилит

juanmf 09.11.2015 01:40

Следует отметить, что System.currentTimeMillis() возвращает то, что ОС считает временем, прошедшим с эпохи Unix. Если ваш пользователь (или сама ОС) изменит время работы ОС между вызовами System.currentTimeMillis(), вы можете получить странные результаты. На nanoTime не влияют изменения часов ОС, поэтому он более надежен.

daiscog 02.06.2016 21:56

Мне пришлось преобразовать endTime в double при делении на 1000000000 (миллиард), чтобы получить секунды: double duration = ((double)endTime - startTime) / 1000000000;

Sam Malayek 23.07.2018 07:12

позаботьтесь об асинхронных методах с этим, так как вам понадобится интерфейс, чтобы знать, когда эти методы закончатся

Gastón Saillén 25.09.2018 16:48

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

jwenting 01.10.2018 10:58

В качестве улучшения лучшим способом извлечения количества пройденных миллисекунд будет следующий: double time = (endTime - startTime) * 1e-6; Он краток, быстрее деления, однозначен в отношении количества десятичных знаков и неявно приведен к двойному с помощью литерала 1e-6 (см. stackoverflow.com/questions/15527198/…)

JJ Brown 10.12.2018 20:38

@JohnGardner Теперь это старомодно. :)

Kröw 18.05.2019 04:29

@ Kröw был уверен, что это так. старое-старое-новое к настоящему моменту?

John Gardner 23.05.2019 21:59

@JamesSchek В каких ситуациях это могло пойти не так? Вы только заявляете, что это может пойти не так, а затем размещаете 2 неработающие ссылки

Ferrybig 01.07.2019 22:13

long startTime = System.currentTimeMillis();
// code goes here
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime; // elapsed time in milliseconds

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

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

Есть несколько способов сделать это. Обычно я просто использую что-то вроде этого:

long start = System.currentTimeMillis();
// ... do something ...
long end = System.currentTimeMillis();

или то же самое с System.nanoTime ();

Для чего-то большего, связанного с эталонным тестированием, похоже, также есть это: http://jetm.void.fm/ Но никогда не пробовал.

Как сказал «скаффман», используйте АОП ИЛИ вы можете использовать переплетение байт-кода во время выполнения, точно так же, как инструменты покрытия методов модульного тестирования используют для прозрачного добавления информации о времени в вызываемые методы.

Вы можете посмотреть код, используемый инструментами с открытым исходным кодом, такими как Emma (http://downloads.sourceforge.net/emma/emma-2.0.5312-src.zip?modtime=1118607545&big_mirror=0). Другой инструмент покрытия с открытым исходным кодом - http://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?download.

Если вам в конце концов удастся сделать то, к чему вы стремились, пожалуйста. поделитесь им с сообществом здесь с помощью вашей задачи / jar-файлов.

Используйте профилировщик (JProfiler, Netbeans Profiler, Visual VM, Eclipse Profiler и т. д.). Вы получите наиболее точные результаты и наименее навязчивые. Они используют встроенный механизм JVM для профилирования, который также может предоставить вам дополнительную информацию, такую ​​как трассировки стека, пути выполнения и, при необходимости, более подробные результаты.

При использовании полностью интегрированного профилировщика профилировать метод очень просто. Щелкните правой кнопкой мыши, Профилировщик -> Добавить к корневым методам. Затем запустите профилировщик, как если бы вы выполняли тестовый запуск или отладчик.

Это также было отличным предложением и одним из тех моментов, когда я прочитал этот ответ. В нашем проекте используется JDeveloper, но я проверил, и, конечно же, у него есть встроенный профилировщик!

Ogre Psalm33 08.10.2008 16:14

Из java 7 build 40 (я думаю) они включили бывший JRockits Flight Recorder в java (поиск Java Mission Control)

Niels Bech Nielsen 17.03.2014 17:30

Конечно же @NielsBechNielsen! oracle.com/technetwork/java/javaseproducts/mission-control/…

Ogre Psalm33 07.07.2014 18:43

Как, например, получить выполнение метода на Java с помощью Visual VM?

petertc 13.11.2014 11:06

Для этого мы используем аннотации AspectJ и Java. Если нам нужно знать время выполнения метода, мы просто аннотируем его. Более продвинутая версия может использовать собственный уровень журнала, который можно включать и отключать во время выполнения.

public @interface Trace {
  boolean showParameters();
}

@Aspect
public class TraceAspect {
  [...]
  @Around("tracePointcut() && @annotation(trace) && !within(TraceAspect)")
  public Object traceAdvice ( ProceedingJintPoint jP, Trace trace ) {

    Object result;
    // initilize timer

    try { 
      result = jp.procced();
    } finally { 
      // calculate execution time 
    }

    return result;
  }
  [...]
}

Небольшой поворот, если вы не используете инструменты и хотите синхронизировать методы с низким временем выполнения: выполняйте его много раз, каждый раз удваивая количество раз, когда он выполняется, пока вы не дойдете до секунды или около того. Таким образом, время вызова System.nanoTime и т. д., А также точность System.nanoTime не сильно влияют на результат.

    int runs = 0, runsPerRound = 10;
    long begin = System.nanoTime(), end;
    do {
        for (int i=0; i<runsPerRound; ++i) timedMethod();
        end = System.nanoTime();
        runs += runsPerRound;
        runsPerRound *= 2;
    } while (runs < Integer.MAX_VALUE / 2 && 1000000000L > end - begin);
    System.out.println("Time for timedMethod() is " + 
        0.000000001 * (end-begin) / runs + " seconds");

Конечно, применяются предостережения об использовании настенных часов: влияние JIT-компиляции, нескольких потоков / процессов и т. д. Таким образом, вам нужно сначала выполнить метод много несколько раз, чтобы JIT-компилятор выполнял свою работу, а затем повторить этот тест несколько раз и занимает наименьшее время выполнения.

Также мы можем использовать класс StopWatch из общего числа Apache для измерения времени.

Образец кода

org.apache.commons.lang.time.StopWatch sw = new org.apache.commons.lang.time.StopWatch();

System.out.println("getEventFilterTreeData :: Start Time : " + sw.getTime());
sw.start();

// Method execution code

sw.stop();
System.out.println("getEventFilterTreeData :: End Time : " + sw.getTime());

Вы можете использовать Perf4j. Очень классная утилита. Использование простое

String watchTag = "target.SomeMethod";
StopWatch stopWatch = new LoggingStopWatch(watchTag);
Result result = null; // Result is a type of a return value of a method
try {
    result = target.SomeMethod();
    stopWatch.stop(watchTag + ".success");
} catch (Exception e) {
    stopWatch.stop(watchTag + ".fail", "Exception was " + e);
    throw e; 
}

Более подробную информацию можно найти в Руководство разработчика

Обновлено: Проект кажется мертвым

Perf4j также может генерировать хороший статистика.

Paaske 28.03.2012 16:00

Действительно хороший код.

http://www.rgagnon.com/javadetails/java-0585.html

import java.util.concurrent.TimeUnit;

long startTime = System.currentTimeMillis();
........
........
........
long finishTime = System.currentTimeMillis();

String diff = millisToShortDHMS(finishTime - startTime);


  /**
   * converts time (in milliseconds) to human-readable format
   *  "<dd:>hh:mm:ss"
   */
  public static String millisToShortDHMS(long duration) {
    String res = "";
    long days  = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration)
                   - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration)
                     - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration)
                   - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
    if (days == 0) {
      res = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }
    else {
      res = String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds);
    }
    return res;
  }

На самом деле вопрос заключался в том, как рассчитать количество времени, которое требуется для метода, а не в том, как его отформатировать. Однако этот вопрос довольно старый (почти четыре года!). Старайтесь не восстанавливать старые потоки, если ответ не добавит чего-то нового и значительного по сравнению с существующими ответами.

Leigh 15.06.2012 12:58

И чтобы добавить оставшиеся миллисекунды до конца, внесите следующие изменения: long millis = TimeUnit.MILLISECONDS.toMillis(duration) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(du‌​ration)); if (days == 0) { res = String.format("%02d:%02d:%02d.%02d", hours, minutes, seconds, millis); } else { res = String.format("%dd%02d:%02d:%02d.%02d", days, hours, minutes, seconds, millis); }

Rick Barkhouse 24.01.2013 02:19

Используя аннотацию AOP / AspectJ и @Loggable из jcabi-аспекты, вы можете сделать это легко и компактно:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

Каждый вызов этого метода будет отправлен в средство ведения журнала SLF4J с уровнем ведения журнала DEBUG. И каждое сообщение журнала будет включать время выполнения.

Давайте, ребята! Никто не упомянул способ сделать это Гуава (что, возможно, круто):

import com.google.common.base.Stopwatch;

Stopwatch timer = Stopwatch.createStarted();
//method invocation
LOG.info("Method took: " + timer.stop());

Приятно то, что Stopwatch.toString () хорошо справляется с выбором единиц времени для измерения. Т.е. если значение маленькое, будет выдано 38 нс, если оно длинное, будет отображаться 5 м 3 с

Еще лучше:

Stopwatch timer = Stopwatch.createUnstarted();
for (...) {
   timer.start();
   methodToTrackTimeFor();
   timer.stop();
   methodNotToTrackTimeFor();
}
LOG.info("Method took: " + timer);

Примечание. Google Guava требует Java 1.6+.

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

Dexter Legaspi 15.12.2014 17:50

@DexterLegaspi Был бы очень заинтересован в вашем опыте! Заботиться, чтобы поделиться?

Siddhartha 19.01.2015 22:30

Параллельное использование секундомера приведет к тому, что вы вызовете start() несколько раз подряд (то же самое для stop()).

Mingwei Samuel 16.08.2019 20:36

new Timer(""){{
    // code to time 
}}.timeMe();



public class Timer {

    private final String timerName;
    private long started;

    public Timer(String timerName) {
        this.timerName = timerName;
        this.started = System.currentTimeMillis();
    }

    public void timeMe() {
        System.out.println(
        String.format("Execution of '%s' takes %dms.", 
                timerName, 
                started-System.currentTimeMillis()));
    }

}

Сворачивание собственного простого класса - хороший выбор, если у вас уже настроена система сборки и зависимый OTS, и вы не хотите беспокоиться о добавлении другого пакета OTS, который включает служебный класс таймера.

Ogre Psalm33 04.04.2013 01:06

System.nanoTime() - довольно точная системная утилита для измерения времени выполнения. Но будьте осторожны, если вы работаете в режиме упреждающего планировщика (по умолчанию), эта утилита фактически измеряет время настенных часов, а не время процессора. Таким образом, вы можете заметить разные значения времени выполнения от запуска к запуску, в зависимости от загрузки системы. Если вы посмотрите на процессорное время, я думаю, что запуск вашей программы в режиме реального времени поможет. Вы должны использовать RT linux. ссылка: Программирование в реальном времени с Linux

Вы можете попробовать этот способ, если хотите знать время.

long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));    

Я изменил код из правильного ответа, чтобы получить результат за секунды:

long startTime = System.nanoTime();

methodCode ...

long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / (Math.pow(10, 9));
Log.v(TAG, "MethodName time (s) = " + duration);

System.currentTimeMillis(); НЕ ЯВЛЯЕТСЯ хорошим подходом для измерения производительности ваших алгоритмов. Он измеряет общее время, в течение которого вы наблюдаете за экраном компьютера. Сюда также входит время, затрачиваемое на все остальное, работающее на вашем компьютере в фоновом режиме. Это может иметь огромное значение, если на вашей рабочей станции работает много программ.

Правильный подход - использование пакета java.lang.management.

С сайта http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking (ссылка на архив):

  • «Пользовательское время» - это время, потраченное на выполнение собственного кода вашего приложения.
  • «Системное время» - это время, затрачиваемое на выполнение кода ОС от имени вашего приложения (например, для ввода-вывода).

Метод getCpuTime() дает вам сумму из них:

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

public class CPUUtils {

    /** Get CPU time in nanoseconds. */
    public static long getCpuTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            bean.getCurrentThreadCpuTime( ) : 0L;
    }

    /** Get user time in nanoseconds. */
    public static long getUserTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            bean.getCurrentThreadUserTime( ) : 0L;
    }

    /** Get system time in nanoseconds. */
    public static long getSystemTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            (bean.getCurrentThreadCpuTime( ) - bean.getCurrentThreadUserTime( )) : 0L;
    }

}

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

Ogre Psalm33 07.04.2014 16:52

Это ответ, который я ищу.

ZhaoGang 06.01.2020 05:14

Измерения производительности на моей машине

  • System.nanoTime() : 750ns
  • System.currentTimeMillis() : 18ns

Как уже упоминалось, System.nanoTime() предназначен для измерения прошедшего времени. Просто помните о стоимости использования внутри цикла или чего-то подобного.

Было бы неплохо, если бы у java была лучшая функциональная поддержка, чтобы действие, которое нужно измерить, можно было бы обернуть в блок:

measure {
   // your operation here
}

В java это можно сделать с помощью анонимных функций, которые выглядят слишком многословно.

public interface Timer {
    void wrap();
}


public class Logger {

    public static void logTime(Timer timer) {
        long start = System.currentTimeMillis();
        timer.wrap();
        System.out.println("" + (System.currentTimeMillis() - start) + "ms");
    }

    public static void main(String a[]) {
        Logger.logTime(new Timer() {
            public void wrap() {
                // Your method here
                timeConsumingOperation();
            }
        });

    }

    public static void timeConsumingOperation() {
        for (int i = 0; i<=10000; i++) {
           System.out.println("i = " +i);
        }
    }
}

Вероятно, можно было бы очистить, используя лямбда-выражения Java 8. drdobbs.com/jvm/lambda-expressions-in-java-8/240166764?pgno=‌ 2

Ogre Psalm33 19.01.2015 16:55

Действительно, начиная с Java 8, java.lang.Runnable является @FunctionalInterface, что означает, что вы можете передать лямбда-выражение любому методу, который принимает Runnable в качестве параметра. Ваш timeThisCode(Runnable r) может просто возвращать миллис / нанометры или более подробное представление прошедшего времени.

Cornel Masson 24.04.2015 15:28

Хорошо, это простой класс, который можно использовать для простого определения времени выполнения ваших функций. Ниже приведен пример.

public class Stopwatch {
    static long startTime;
    static long splitTime;
    static long endTime;

    public Stopwatch() {
        start();
    }

    public void start() {
        startTime = System.currentTimeMillis();
        splitTime = System.currentTimeMillis();
        endTime = System.currentTimeMillis();
    }

    public void split() {
        split("");
    }

    public void split(String tag) {
        endTime = System.currentTimeMillis();
        System.out.println("Split time for [" + tag + "]: " + (endTime - splitTime) + " ms");
        splitTime = endTime;
    }

    public void end() {
        end("");
    }
    public void end(String tag) {
        endTime = System.currentTimeMillis();
        System.out.println("Final time for [" + tag + "]: " + (endTime - startTime) + " ms");
    }
}

Пример использования:

public static Schedule getSchedule(Activity activity_context) {
        String scheduleJson = null;
        Schedule schedule = null;
/*->*/  Stopwatch stopwatch = new Stopwatch();

        InputStream scheduleJsonInputStream = activity_context.getResources().openRawResource(R.raw.skating_times);
/*->*/  stopwatch.split("open raw resource");

        scheduleJson = FileToString.convertStreamToString(scheduleJsonInputStream);
/*->*/  stopwatch.split("file to string");

        schedule = new Gson().fromJson(scheduleJson, Schedule.class);
/*->*/  stopwatch.split("parse Json");
/*->*/  stopwatch.end("Method getSchedule"); 
    return schedule;
}

Пример вывода на консоль:

Split time for [file to string]: 672 ms
Split time for [parse Json]: 893 ms
Final time for [get Schedule]: 1565 ms

Используя Мгновенный и Продолжительность из нового API Java 8,

Instant start = Instant.now();
Thread.sleep(5000);
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

выходы,

PT5S

Спасибо, как я могу вывести результат, не имея ПТ впереди?

java123999 16.03.2016 18:31

Проблема с методом заключается в том, что Instant не нарушает точность в миллисекундах и наносекундах. Ссылка: stackoverflow.com/questions/20689055/…

prashantsunkari 13.04.2017 01:56

@ java123999: Вы можете вызвать в Duration.between(start, end).getSeconds(). Duration также имеет методы для преобразования в другие единицы времени, например toMillis(), который преобразуется в миллисекунды.

Emil Lunde 29.05.2018 16:29

В Java 8 представлен новый класс Instant. Согласно документу:

Instant represents the start of a nanosecond on the time line. This class is useful for generating a time stamp to represent machine time. The range of an instant requires the storage of a number larger than a long. To achieve this, the class stores a long representing epoch-seconds and an int representing nanosecond-of-second, which will always be between 0 and 999,999,999. The epoch-seconds are measured from the standard Java epoch of 1970-01-01T00:00:00Z where instants after the epoch have positive values, and earlier instants have negative values. For both the epoch-second and nanosecond parts, a larger value is always later on the time-line than a smaller value.

Это можно использовать как:

Instant start = Instant.now();
try {
    Thread.sleep(7000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

Он печатает PT7.001S.

Spring предоставляет служебный класс org.springframework.util.StopWatch согласно JavaDoc:

Simple stop watch, allowing for timing of a number of tasks, exposing total running time and running time for each named task.

Использование:

StopWatch stopWatch = new StopWatch("Performance Test Result");

stopWatch.start("Method 1");
doSomething1();//method to test
stopWatch.stop();

stopWatch.start("Method 2");
doSomething2();//method to test
stopWatch.stop();

System.out.println(stopWatch.prettyPrint());

Выход:

StopWatch 'Performance Test Result': running time (millis) = 12829
-----------------------------------------
ms     %     Task name
-----------------------------------------
11907  036%  Method 1
00922  064%  Method 2

С аспектами:

@Around("execution(* my.package..*.*(..))")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    Object retVal = joinPoint.proceed();
    stopWatch.stop();
    log.info(" execution time: " + stopWatch.getTotalTimeMillis() + " ms");
    return retVal;
}

Можно ли использовать это с AspectJ?

zygimantus 20.10.2015 21:53

Вы можете использовать javaagent для изменения байтов класса java, динамически добавлять коды монитора. На github есть несколько инструментов с открытым исходным кодом, которые могут сделать это за вас. Если вы хотите сделать это самостоятельно, просто реализуйте javaagent, используйте javassist, чтобы изменить методы, которые вы хотите отслеживать, и код монитора перед возвратом вашего метода. Он чистый, и вы можете отслеживать системы, у которых даже нет исходного кода .

В Java 8 вы также можете делать что-то подобное с каждым обычным методы:

Object returnValue = TimeIt.printTime(() -> methodeWithReturnValue());
//do stuff with your returnValue

с TimeIt нравится:

public class TimeIt {

public static <T> T printTime(Callable<T> task) {
    T call = null;
    try {
        long startTime = System.currentTimeMillis();
        call = task.call();
        System.out.print((System.currentTimeMillis() - startTime) / 1000d + "s");
    } catch (Exception e) {
        //...
    }
    return call;
}
}

С помощью этого метода вы можете легко измерить время в любом месте вашего кода, не нарушая его. В этом простом примере я просто печатаю время. Можете ли вы добавить переключатель для TimeIt, например только напечатать время в DebugMode или что-то в этом роде.

Если вы работаете с Функция, вы можете сделать что-то вроде этого:

Function<Integer, Integer> yourFunction= (n) -> {
        return IntStream.range(0, n).reduce(0, (a, b) -> a + b);
    };

Integer returnValue = TimeIt.printTime2(yourFunction).apply(10000);
//do stuff with your returnValue

public static <T, R> Function<T, R> printTime2(Function<T, R> task) {
    return (t) -> {
        long startTime = System.currentTimeMillis();
        R apply = task.apply(t);
        System.out.print((System.currentTimeMillis() - startTime) / 1000d
                + "s");
        return apply;
    };
}

Это выглядит намного лучше, чем другие решения. Это ближе к Spring AOP, но легче. Правда java 8 способ! +1 Спасибо!

Amit Kumar 05.12.2017 17:09

Возможно, вам это нравится, потому что Стефан использует новые причудливые java-функции. Но я думаю, что это очень трудно читать и понимать.

Stimpson Cat 05.07.2019 12:25

Собрал все возможные пути в одно место.

Датировать

Date startDate = Calendar.getInstance().getTime();
long d_StartTime = new Date().getTime();
Thread.sleep(1000 * 4);
Date endDate = Calendar.getInstance().getTime();
long d_endTime = new Date().getTime();
System.out.format("StartDate : %s, EndDate : %s \n", startDate, endDate);
System.out.format("Milli = %s, ( D_Start : %s, D_End : %s ) \n", (d_endTime - d_StartTime),d_StartTime, d_endTime);

System.currentTimeMillis ()

long startTime = System.currentTimeMillis();
Thread.sleep(1000 * 4);
long endTime = System.currentTimeMillis();
long duration = (endTime - startTime);  
System.out.format("Milli = %s, ( S_Start : %s, S_End : %s ) \n", duration, startTime, endTime );
System.out.println("Human-Readable format : "+millisToShortDHMS( duration ) );

Человекочитаемый Формат

public static String millisToShortDHMS(long duration) {
    String res = "";    // java.util.concurrent.TimeUnit;
    long days       = TimeUnit.MILLISECONDS.toDays(duration);
    long hours      = TimeUnit.MILLISECONDS.toHours(duration) -
                      TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
    long minutes    = TimeUnit.MILLISECONDS.toMinutes(duration) -
                      TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
    long seconds    = TimeUnit.MILLISECONDS.toSeconds(duration) -
                      TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
    long millis     = TimeUnit.MILLISECONDS.toMillis(duration) - 
                      TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration));

    if (days == 0)      res = String.format("%02d:%02d:%02d.%04d", hours, minutes, seconds, millis);
    else                res = String.format("%dd %02d:%02d:%02d.%04d", days, hours, minutes, seconds, millis);
    return res;
}

Гуава: GoogleСекундомерJAR «Секундомер измеряет прошедшее время в наносекундах.

com.google.common.base.Stopwatch g_SW = Stopwatch.createUnstarted();
g_SW.start();
Thread.sleep(1000 * 4);
g_SW.stop();
System.out.println("Google StopWatch  : "+g_SW);

Apache Commons LangJAR «Секундомер предоставляет удобный API для таймингов.

org.apache.commons.lang3.time.StopWatch sw = new StopWatch();
sw.start();     
Thread.sleep(1000 * 4);     
sw.stop();
System.out.println("Apache StopWatch  : "+ millisToShortDHMS(sw.getTime()) );

JODA-TIME

public static void jodaTime() throws InterruptedException, ParseException{
    java.text.SimpleDateFormat ms_SDF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
    String start = ms_SDF.format( new Date() ); // java.util.Date

    Thread.sleep(10000);

    String end = ms_SDF.format( new Date() );       
    System.out.println("Start:"+start+"\t Stop:"+end);

    Date date_1 = ms_SDF.parse(start);
    Date date_2 = ms_SDF.parse(end);        
    Interval interval = new org.joda.time.Interval( date_1.getTime(), date_2.getTime() );
    Period period = interval.toPeriod(); //org.joda.time.Period

    System.out.format("%dY/%dM/%dD, %02d:%02d:%02d.%04d \n", 
        period.getYears(), period.getMonths(), period.getDays(),
        period.getHours(), period.getMinutes(), period.getSeconds(), period.getMillis());
}

API даты и времени Java из Java 8 «Объект Продолжительность представляет период времени между двумя объектами Мгновенный.

Instant start = java.time.Instant.now();
    Thread.sleep(1000);
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.println( between ); // PT1.001S
System.out.format("%dD, %02d:%02d:%02d.%04d \n", between.toDays(),
        between.toHours(), between.toMinutes(), between.getSeconds(), between.toMillis()); // 0D, 00:00:01.1001 

Spring Framework предоставляет служебный класс Секундомер для измерения прошедшего времени в Java.

StopWatch sw = new org.springframework.util.StopWatch();
sw.start("Method-1"); // Start a named task
    Thread.sleep(500);
sw.stop();

sw.start("Method-2");
    Thread.sleep(300);
sw.stop();

sw.start("Method-3");
    Thread.sleep(200);
sw.stop();

System.out.println("Total time in milliseconds for all tasks :\n"+sw.getTotalTimeMillis());
System.out.println("Table describing all tasks performed :\n"+sw.prettyPrint());

System.out.format("Time taken by the last task : [%s]:[%d]", 
        sw.getLastTaskName(),sw.getLastTaskTimeMillis());

System.out.println("\n Array of the data for tasks performed « Task Name: Time Taken");
TaskInfo[] listofTasks = sw.getTaskInfo();
for (TaskInfo task : listofTasks) {
    System.out.format("[%s]:[%d]\n", 
            task.getTaskName(), task.getTimeMillis());
}

Выход:

Total time in milliseconds for all tasks :
999
Table describing all tasks performed :
StopWatch '': running time (millis) = 999
-----------------------------------------
ms     %     Task name
-----------------------------------------
00500  050%  Method-1
00299  030%  Method-2
00200  020%  Method-3

Time taken by the last task : [Method-3]:[200]
 Array of the data for tasks performed « Task Name: Time Taken
[Method-1]:[500]
[Method-2]:[299]
[Method-3]:[200]

Секундомер Guava, Apache Commons и Spring Framework не являются потокобезопасными. Небезопасно для производственного использования.

Deepak Puthraya 12.06.2018 22:25

@DeepakPuthraya, тогда какую библиотеку использовать, которая безопасна для производственного использования?

Gaurav 24.09.2019 10:24

@DeepakPuthraya, вы можете использовать Java 8, предоставленный API времени Java. Это просто.

Yash 24.09.2019 10:48

ИМО, этот пост выиграл бы, если бы каждое решение также показывало вывод системных выходов.

BAERUS 28.04.2020 18:23

JEP 230: Пакет Microbenchmark

К вашему сведению, JEP 230: Пакет Microbenchmark - это проект OpenJDK для:

Add a basic suite of microbenchmarks to the JDK source code, and make it easy for developers to run existing microbenchmarks and create new ones.

Эта функция появилась в Java 12.

Обвязка Java Microbenchmark (JMH)

Для более ранних версий Java обратите внимание на проект Обвязка Java Microbenchmark (JMH), на котором основан JEP 230.

Вот довольно напечатанная строка, готовая отформатированная, прошедшая секунда, аналогичная времени поиска Google, затраченному на поиск:

        long startTime = System.nanoTime();
        //  ... methodToTime();
        long endTime = System.nanoTime();
        long duration = (endTime - startTime);
        long seconds = (duration / 1000) % 60;
        // formatedSeconds = (0.xy seconds)
        String formatedSeconds = String.format("(0.%d seconds)", seconds);
        System.out.println("formatedSeconds = "+ formatedSeconds);
        // i.e actual formatedSeconds = (0.52 seconds)

nonoTime не равно 1000 секунды. ваша математика предполагает getTime, который составляет миллисекунду. лучше сделать / 1e6, чтобы получить миллисекунды.

simbo1905 14.02.2018 10:38

Я реализовал простой таймер, и считаю, что он действительно полезен:

public class Timer{
    private static long start_time;

    public static double tic(){
        return start_time = System.nanoTime();
    }

    public static double toc(){
        return (System.nanoTime()-start_time)/1000000000.0;
    }

}

Таким образом вы можете рассчитать время для одного или нескольких действий:

Timer.tic();
// Code 1
System.out.println("Code 1 runtime: "+Timer.toc()+" seconds.");
// Code 2
System.out.println("(Code 1 + Code 2) runtime: "+Timer.toc()+"seconds");
Timer.tic();
// Code 3
System.out.println("Code 3 runtime: "+Timer.toc()+" seconds.");

Стратегия, которая работает для меня в java ee, заключалась в следующем:

  1. Создайте класс с методом, аннотированным @AroundInvoke;

    @Singleton
    public class TimedInterceptor implements Serializable {
    
        @AroundInvoke
        public Object logMethod(InvocationContext ic) throws Exception {
            Date start = new Date();
            Object result = ic.proceed();
            Date end = new Date();
            System.out.println("time: " + (end.getTime - start.getTime()));
            return result;
        }
    }
    
  2. Отметьте метод, который вы хотите отслеживать:

    @Interceptors(TimedInterceptor.class)
    public void onMessage(final Message message) { ... 
    

Надеюсь, это поможет.

Вы можете использовать библиотеку Метрики, которая предоставляет различные измерительные инструменты. Добавить зависимость:

<dependencies>
    <dependency>
        <groupId>io.dropwizard.metrics</groupId>
        <artifactId>metrics-core</artifactId>
        <version>${metrics.version}</version>
    </dependency>
</dependencies>

И настройте его для своей среды.

Методы можно аннотировать с помощью @Timed:

@Timed
public void exampleMethod(){
    // some code
}

или фрагмент кода, обернутый Таймер:

final Timer timer = metricsRegistry.timer("some_name");
final Timer.Context context = timer.time();
// timed code
context.stop();

Агрегированные метрики можно экспортировать в консоль, JMX, CSV или другой формат.

Пример вывода метрики @Timed:

com.example.ExampleService.exampleMethod
             count = 2
         mean rate = 3.11 calls/minute
     1-minute rate = 0.96 calls/minute
     5-minute rate = 0.20 calls/minute
    15-minute rate = 0.07 calls/minute
               min = 17.01 milliseconds
               max = 1006.68 milliseconds
              mean = 511.84 milliseconds
            stddev = 699.80 milliseconds
            median = 511.84 milliseconds
              75% <= 1006.68 milliseconds
              95% <= 1006.68 milliseconds
              98% <= 1006.68 milliseconds
              99% <= 1006.68 milliseconds
            99.9% <= 1006.68 milliseconds

Вы можете использовать класс секундомера из проекта ядра Spring:

Код:

StopWatch stopWatch = new StopWatch()
stopWatch.start();  //start stopwatch
// write your function or line of code.
stopWatch.stop();  //stop stopwatch
stopWatch.getTotalTimeMillis() ; ///get total time

Документация для секундомера: Простой секундомер, позволяющий отсчитывать время для ряда задач, показывая общее время выполнения и время выполнения для каждой названной задачи. Скрывает использование System.currentTimeMillis (), улучшая читаемость кода приложения и снижая вероятность ошибок вычислений. Обратите внимание, что этот объект не предназначен для обеспечения многопоточности и не использует синхронизацию. Этот класс обычно используется для проверки производительности во время проверки концепции и в процессе разработки, а не как часть производственных приложений.

Я написал метод для вывода времени выполнения метода в удобочитаемой форме. Например, чтобы вычислить факториал 1 миллиона, потребуется примерно 9 минут. Таким образом, время выполнения печатается как:

Execution Time: 9 Minutes, 36 Seconds, 237 MicroSeconds, 806193 NanoSeconds

Код здесь:

public class series
{
    public static void main(String[] args)
    {
        long startTime = System.nanoTime();

        long n = 10_00_000;
        printFactorial(n);

        long endTime = System.nanoTime();
        printExecutionTime(startTime, endTime);

    }

    public static void printExecutionTime(long startTime, long endTime)
    {
        long time_ns = endTime - startTime;
        long time_ms = TimeUnit.NANOSECONDS.toMillis(time_ns);
        long time_sec = TimeUnit.NANOSECONDS.toSeconds(time_ns);
        long time_min = TimeUnit.NANOSECONDS.toMinutes(time_ns);
        long time_hour = TimeUnit.NANOSECONDS.toHours(time_ns);

        System.out.print("\nExecution Time: ");
        if (time_hour > 0)
            System.out.print(time_hour + " Hours, ");
        if (time_min > 0)
            System.out.print(time_min % 60 + " Minutes, ");
        if (time_sec > 0)
            System.out.print(time_sec % 60 + " Seconds, ");
        if (time_ms > 0)
            System.out.print(time_ms % 1E+3 + " MicroSeconds, ");
        if (time_ns > 0)
            System.out.print(time_ns % 1E+6 + " NanoSeconds");
    }
}

Для java 8+ другое возможное решение (более общее, в стиле func и без аспектов) могло бы заключаться в создании некоторого служебного метода, принимающего код в качестве параметра

public static <T> T timed (String description, Consumer<String> out, Supplier<T> code) {
    final LocalDateTime start = LocalDateTime.now ();
    T res = code.get ();
    final long execTime = Duration.between (start, LocalDateTime.now ()).toMillis ();
    out.accept (String.format ("%s: %d ms", description, execTime));
    return res;
}

И код вызова может быть что-то вроде этого:

public static void main (String[] args) throws InterruptedException {
    timed ("Simple example", System.out::println, Timing::myCode);
}

public static Object myCode () {
    try {
        Thread.sleep (1500);
    } catch (InterruptedException e) {
        e.printStackTrace ();
    }
    return null;
}

Чистый код Java SE, нет необходимости добавлять зависимости, используя TimeTracedExecuter:

public static void main(String[] args) {

    Integer square = new TimeTracedExecutor<>(Main::calculateSquare)
                .executeWithInput("calculate square of num",5,logger);

}
public static int calculateSquare(int num){
    return num*num;
}

Результат будет примерно таким:

INFO: It took 3 milliseconds to calculate square of num

Настраиваемый многоразовый класс: TimeTracedExecutor

import java.text.NumberFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.function.Function;
import java.util.logging.Logger;

public class TimeTracedExecutor<T,R> {
    Function<T,R> methodToExecute;

    public TimeTracedExecutor(Function<T, R> methodToExecute) {
        this.methodToExecute = methodToExecute;
    }

    public R executeWithInput(String taskDescription, T t, Logger logger){
        Instant start = Instant.now();
        R r= methodToExecute.apply(t);
        Instant finish = Instant.now();
        String format = "It took %s milliseconds to "+taskDescription;
        String elapsedTime = NumberFormat.getNumberInstance().format(Duration.between(start, finish).toMillis());
        logger.info(String.format(format, elapsedTime));
        return r;
    }
}

В Spring framework у нас есть вызов StopWatch (org.springframework.util.StopWatch)

//measuring elapsed time using Spring StopWatch
        StopWatch watch = new StopWatch();
        watch.start();
        for(int i=0; i< 1000; i++){
            Object obj = new Object();
        }
        watch.stop();
        System.out.println("Total execution time to create 1000 objects in Java using StopWatch in millis: "
                + watch.getTotalTimeMillis());

Из документов: This class is normally used to verify performance during proof-of-concept work and in development, rather than as part of production applications.

q99 17.06.2020 18:59

@ q99 Правда, такую ​​логику мы не внедряем в производственную среду, прежде чем переносить ее в производственную среду, нам нужно протестировать

Bhaskara Arani 19.06.2020 12:05

Другие вопросы по теме