Timer для таких вещей, как определение времени выполнения задачи и т. д.?Большинство поисковых запросов в Google возвращают результаты для таймеров, которые планируют потоки и задачи, что мне не нужно.
JAMon API - это бесплатный, простой, высокопроизводительный, потокобезопасный Java API, который позволяет разработчикам легко контролировать производительность и масштабируемость производственных приложений. JAMon отслеживает совпадения, время выполнения (общее, среднее, минимальное, максимальное, стандартное отклонение) и многое другое. http://jamonapi.sourceforge.net/ скачать: http://sourceforge.net/project/showfiles.php?group_id=96550
Вы также можете посмотреть класс Секундомер Apache Commons Lang. Простой, но полезный служебный класс.
Да, секундомер отлично подходит для этого.
Java 8 с использованием класса Instant: stackoverflow.com/a/30975902/1216775




Вероятно, это не то, что вы хотели, чтобы я сказал, но это хорошее применение АОП. Оберните прокси-перехватчик вокруг своего метода и отсчитайте время.
К сожалению, вопрос о том, что, почему и как в АОП выходит за рамки этого ответа, но я бы сделал это именно так.
Обновлено: Вот ссылка до Spring AOP, чтобы вы начали, если вы заинтересованы. Это наиболее доступная реализация АОП, которую Iive встречал для java.
Кроме того, учитывая очень простые предложения всех остальных, я должен добавить, что АОП предназначен для случаев, когда вы не хотите, чтобы такие вещи, как время, вторгались в ваш код. Но во многих случаях такой простой и легкий подход подходит.
Вот руководство о том, как это сделать с помощью Spring: veerasundar.com/blog/2010/01/…
Я согласен с простым ответом. Работает для меня.
long startTime = System.currentTimeMillis();
doReallyLongThing();
long endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " milliseconds");
Работает неплохо. Разрешение, очевидно, составляет всего миллисекунды, вы можете добиться большего с помощью System.nanoTime (). Для обоих есть некоторые ограничения (срезы расписания операционной системы и т. д.), Но это работает довольно хорошо.
Среднее значение за пару прогонов (чем больше, тем лучше), и вы получите неплохое представление.
На самом деле System.currentTimeMillis () точен только выше 15 мс. При действительно низких значениях этому нельзя доверять. Решением для этого (как уже упоминалось) является System.nanoTime ();
Хорошо, я собирался принять это как официальный ответ, пока не прочитал комментарий Стива Дж. Отличный лакомый кусочек, Стив!
nanoTime () не гарантирует точность лучше, чем currentTimeMillis, но многие реализации JVM действительно имеют лучшую точность с nanoTime.
@JamesSchek Вам действительно нужно следить за своей формулировкой, как я уже упоминал в этом идентичном комментарии в другом месте; nanoTime гарантированно будет по крайней мере столь же решительный как currentTimeMillis. docs.oracle.com/javase/7/docs/api/java/lang/…
Одно небольшое преимущество currentTimeMillis заключается в том, что это фактическая временная метка, и ее можно также использовать для регистрации времени начала / окончания, в то время как nanoTime "может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системы или стены. время часов ".
Если ты хочешь настенные часы
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
Это (или использование System.currentTimeMillis ()) похоже на то, как это обычно делается в Java ... что я все равно видел. Меня все еще слегка удивляет, что нет удобного встроенного класса, такого как Timer t = new Timer (); Строка s = t.getElapsed (формат); так далее...
nanoTime не гарантирует лучшей точности, чем currentTimeMillis (), хотя обычно это так. форумы.sun.com/thread.jspa?messageID=9460663 и simongbrown.com/blog/2007/08/20/…
Конечно, всегда важно помнить о подводных камнях микротестирования, таких как оптимизация компилятора / JVM, которая может исказить результат = 8-)
В блоке finally нет необходимости, так как endTime не будет использоваться при возникновении исключения.
Из javadoc для System.currentTimeMillis () "... многие операционные системы измеряют время в единицах десятков миллисекунд". И это правда, в моем окне с Windows это примерно 16 мс. Помните, что там два часа. Поэтому никогда не используйте currentTimeMillis для измерения прошедшего времени. Если вам нужны миллисекунды, просто разделите результат на 1 миллион.
если между временем начала и окончания поток был приостановлен, время окончания фактически также будет отражать время приостановки. поэтому конечным началом не будет фактическое время, потраченное Thread на выполнение.
Хорошо, это хорошо. Но как ОБЪЕДИНИТЬ ТЕСТИРОВАНИЕ этого поведения? т.е. я хочу подтвердить, что метод возвращает время выполнения, которое является разницей между endTime и startTime.
@JamesSchek Будьте осторожны со своей формулировкой, nanoTime гарантированно будет по крайней мере столь же решительный как currentTimeMillis. docs.oracle.com/javase/7/docs/api/java/lang/…
@ OgrePsalm33 В Java 7 есть класс Timer, но он используется для планирования задач.
@ChthonicProject Ну конечно. В моем примере имя класса было просто фиктивным представлением.
Этот ответ не совсем правильный, проверьте мой ответ, если вы ищете время, затрачиваемое только на ваше приложение.
Пожалуйста, обратитесь к этому ответу stackoverflow.com/a/3383047/870547, чтобы сделать это на Java 8 способом
Это секундомер, который я сделал, он позволяет статически добавлять именованные таймеры. Его очень просто использовать, см. Класс DocBlock. gist.github.com/juanmf/4147a9b7010c7b04c003 вы хотите поместить его в свой пакет утилит
Следует отметить, что System.currentTimeMillis() возвращает то, что ОС считает временем, прошедшим с эпохи Unix. Если ваш пользователь (или сама ОС) изменит время работы ОС между вызовами System.currentTimeMillis(), вы можете получить странные результаты. На nanoTime не влияют изменения часов ОС, поэтому он более надежен.
Мне пришлось преобразовать endTime в double при делении на 1000000000 (миллиард), чтобы получить секунды: double duration = ((double)endTime - startTime) / 1000000000;
позаботьтесь об асинхронных методах с этим, так как вам понадобится интерфейс, чтобы знать, когда эти методы закончатся
также имейте в виду, что число, которое вы получите, немного зависит от времени, необходимого для выполнения вызовов для получения отметок времени.
В качестве улучшения лучшим способом извлечения количества пройденных миллисекунд будет следующий: double time = (endTime - startTime) * 1e-6; Он краток, быстрее деления, однозначен в отношении количества десятичных знаков и неявно приведен к двойному с помощью литерала 1e-6 (см. stackoverflow.com/questions/15527198/…)
@JohnGardner Теперь это старомодно. :)
@ Kröw был уверен, что это так. старое-старое-новое к настоящему моменту?
@JamesSchek В каких ситуациях это могло пойти не так? Вы только заявляете, что это может пойти не так, а затем размещаете 2 неработающие ссылки
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, но я проверил, и, конечно же, у него есть встроенный профилировщик!
Из java 7 build 40 (я думаю) они включили бывший JRockits Flight Recorder в java (поиск Java Mission Control)
Конечно же @NielsBechNielsen! oracle.com/technetwork/java/javaseproducts/mission-control/…
Как, например, получить выполнение метода на Java с помощью Visual VM?
Для этого мы используем аннотации 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 также может генерировать хороший статистика.
Действительно хороший код.
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;
}
На самом деле вопрос заключался в том, как рассчитать количество времени, которое требуется для метода, а не в том, как его отформатировать. Однако этот вопрос довольно старый (почти четыре года!). Старайтесь не восстанавливать старые потоки, если ответ не добавит чего-то нового и значительного по сравнению с существующими ответами.
И чтобы добавить оставшиеся миллисекунды до конца, внесите следующие изменения: long millis = TimeUnit.MILLISECONDS.toMillis(duration) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration)); 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); }
Используя аннотацию 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 не является потокобезопасным. я усвоил это на собственном горьком опыте.
@DexterLegaspi Был бы очень заинтересован в вашем опыте! Заботиться, чтобы поделиться?
Параллельное использование секундомера приведет к тому, что вы вызовете start() несколько раз подряд (то же самое для stop()).
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, который включает служебный класс таймера.
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;
}
}
Это определенно хороший момент, поскольку «время пользователя» (время настенных часов) не всегда является отличным показателем производительности, особенно в многопоточной программе.
Это ответ, который я ищу.
Измерения производительности на моей машине
System.nanoTime() : 750nsSystem.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
Действительно, начиная с Java 8, java.lang.Runnable является @FunctionalInterface, что означает, что вы можете передать лямбда-выражение любому методу, который принимает Runnable в качестве параметра. Ваш timeThisCode(Runnable r) может просто возвращать миллис / нанометры или более подробное представление прошедшего времени.
Хорошо, это простой класс, который можно использовать для простого определения времени выполнения ваших функций. Ниже приведен пример.
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
Спасибо, как я могу вывести результат, не имея ПТ впереди?
Проблема с методом заключается в том, что Instant не нарушает точность в миллисекундах и наносекундах. Ссылка: stackoverflow.com/questions/20689055/…
@ java123999: Вы можете вызвать в Duration.between(start, end).getSeconds(). Duration также имеет методы для преобразования в другие единицы времени, например toMillis(), который преобразуется в миллисекунды.
В 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?
Вы можете использовать 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 Спасибо!
Возможно, вам это нравится, потому что Стефан использует новые причудливые java-функции. Но я думаю, что это очень трудно читать и понимать.
Собрал все возможные пути в одно место.
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 не являются потокобезопасными. Небезопасно для производственного использования.
@DeepakPuthraya, тогда какую библиотеку использовать, которая безопасна для производственного использования?
@DeepakPuthraya, вы можете использовать Java 8, предоставленный API времени Java. Это просто.
ИМО, этот пост выиграл бы, если бы каждое решение также показывало вывод системных выходов.
К вашему сведению, 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 обратите внимание на проект Обвязка 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, чтобы получить миллисекунды.
Я реализовал простой таймер, и считаю, что он действительно полезен:
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, заключалась в следующем:
Создайте класс с методом, аннотированным @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;
}
}
Отметьте метод, который вы хотите отслеживать:
@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 Правда, такую логику мы не внедряем в производственную среду, прежде чем переносить ее в производственную среду, нам нужно протестировать
Позже аналогичный Вопрос: Как написать правильный микротест на Java?