Что является чистым способом выполнения кода в Java?
Это может быть удобно для определения времени выполнения кода, чтобы вы знали, как много времени займет процесс. Тем не менее, я нахожу общий способ сделать это неаккуратным, поскольку предполагается, что он имеет одинаковые отступы, что затрудняет чтение того, что на самом деле рассчитано.
long start = System.nanoTime();
// The code you want to time
long end = System.nanoTime();
System.out.printf("That took: %d ms.%n", TimeUnit.NANOSECONDS.toMillis(end - start));
Попытка
Я придумал следующее, это выглядит намного лучше, есть несколько преимуществ и недостатков:
Преимущества:
- Понятно, что рассчитывается из-за отступа
- Он автоматически выведет, сколько времени прошло после завершения кода
Недостатки:
- Это не так
AutoClosable
должен быть использован (уверен) - Это создает новый экземпляр
TimeCode
что не хорошо - Переменные, объявленные в
try
блок не доступен за его пределами
Это можно использовать так:
try (TimeCode t = new TimeCode()) {
// The stuff you want to time
}
Код, который делает это возможным:
class TimeCode implements AutoCloseable {
private long startTime;
public TimeCode() {
this.startTime = System.nanoTime();
}
@Override
public void close() throws Exception {
long endTime = System.nanoTime();
System.out.printf("That took: %d ms%n",
TimeUnit.NANOSECONDS.toMillis(endTime - this.startTime));
}
}
Вопрос
Мой вопрос:
- Мой метод на самом деле так плох, как я думаю,
- Есть ли лучший способ для тайм-кода выполнения в Java, где вы можете четко видеть, что рассчитывается по времени, или я просто должен согласиться на что-то вроде моего первого блока кода.
4 ответа
Вы решение просто отлично.
Менее выразительный способ - обернуть ваш код в лямбду.
public void timeCode(Runnable code) {
...
try {
code.run();
} catch ...
}
...
}
timeCode(() -> { ...code to time... });
Вы, вероятно, хотели бы перехватить проверенные исключения и передать их в какое-то исключение времени выполнения или что-то еще.
Ваш метод великолепен как есть. Мы используем что-то подобное профессионально, но написано на C#.
Одна вещь, которую я потенциально мог бы добавить, это правильная поддержка журналирования, чтобы вы могли переключать эти показатели производительности или иметь их на уровне отладки или информации.
Дополнительные улучшения, которые я хотел бы рассмотреть, - это создание некоторого статического состояния приложения (злоупотребление локальными потоками), чтобы вы могли вкладывать эти разделы и получать сводные разбивки.
Смотрите https://github.com/aikar/minecraft-timings для библиотеки, которая делает это для моддинга Minecraft (написано на Java).
Я думаю, что предложенное решение в тексте вопроса слишком косвенное и не идиоматическое, чтобы быть оптимальным для производственного кода. (Но это похоже на аккуратный инструмент, чтобы быстро получить материал во время разработки.)
И проект Guava, и Apache Commons включают классы секундомера. Используя любой из них, код будет легче читать и понимать, и они также обладают большей функциональностью.
Даже без использования оператора try-with-resource измеряемая секция может быть заключена в блок для улучшения ясности:
// Do things that shouldn't be measured
{
Stopwatch watch = Stopwatch.createStarted();
// Do things that should be measured
System.out.println("Duration: " + watch.elapsed(TimeUnit.SECONDS) + " s");
}
Вместо того, чтобы каждый раз вызывать методы производительности, запишите аспект.
@Pointcut("(execution(* com.resources.delegate.*.*(..)) "
+ "|| execution(* com.resources.implementation.*.*(..))) ")
public void resourceLayerPointCut() {
}
@Pointcut("(execution(* com.models.delegate.*.*(..)) "
+ "|| execution(* com.repo.implementation.*.*(..))) ")
public void exclusionsPointcut() {
}
Вокруг приведен совет, написанный для вашего метода, он напечатает как время начала, так и время окончания. Вам не нужно звонить каждый раз.
@Around(value = "resourceLayerPointCut() && exclusionsPointcut()")
public Object aroundResourceLayerMethods(ProceedingJoinPoint code) throws Throwable {
long startTime = System.currentTimeMillis();
Object returnValue = null;
try {
//This will call your methods
returnValue = code.proceed();
} catch (Throwable e) {
log(joinPoint, startTime, returnValue, Layer.ResourceLayer, true);
throw (e);
}
long endTime = System.currentTimeMillis();
System.out.printf("That took: %d ms%n", endTime - this.startTime);
return returnValue;
}