在 Java 中计时代码执行的简洁方法是什么?
What's a clean way to time code execution in 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 中是否有更好的时间代码执行方式,您可以清楚地看到正在计时的内容,或者我是否只需要满足于我的第一个代码块。
你的方法很好。我们在专业上使用类似的东西,但用 C# 编写。
我可能会添加的一件事是适当的日志记录支持,以便您可以切换这些性能数字,或者将它们置于调试或信息级别。
我会考虑的其他改进是创建一些静态应用程序状态(滥用线程局部变量),以便您可以嵌套这些部分,并进行摘要细分。
请参阅 https://github.com/aikar/minecraft-timings 了解为 minecraft 模组执行此操作的库(用 java 编写)。
你的解决方案很好。
一种表达能力较差的方法是将要计时的代码包装在 lambda 中。
public void timeCode(Runnable code) {
...
try {
code.run();
} catch ...
}
...
}
timeCode(() -> { ...code to time... });
您可能希望捕获已检查的异常并将它们传递给某个运行时异常或其他任何异常。
我认为问题文本中建议的解决方案过于间接和非惯用语不适合生产代码。 (但它看起来像是一个在开发过程中快速获取事物计时的好工具。)
Guava project and the 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");
}
为代码执行计时可以很方便,这样您就可以知道事情需要多长时间。但是,我发现这是草率完成的常见方式,因为它应该具有相同的缩进,这使得阅读实际计时的内容变得更加困难。
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 中是否有更好的时间代码执行方式,您可以清楚地看到正在计时的内容,或者我是否只需要满足于我的第一个代码块。
你的方法很好。我们在专业上使用类似的东西,但用 C# 编写。
我可能会添加的一件事是适当的日志记录支持,以便您可以切换这些性能数字,或者将它们置于调试或信息级别。
我会考虑的其他改进是创建一些静态应用程序状态(滥用线程局部变量),以便您可以嵌套这些部分,并进行摘要细分。
请参阅 https://github.com/aikar/minecraft-timings 了解为 minecraft 模组执行此操作的库(用 java 编写)。
你的解决方案很好。
一种表达能力较差的方法是将要计时的代码包装在 lambda 中。
public void timeCode(Runnable code) {
...
try {
code.run();
} catch ...
}
...
}
timeCode(() -> { ...code to time... });
您可能希望捕获已检查的异常并将它们传递给某个运行时异常或其他任何异常。
我认为问题文本中建议的解决方案过于间接和非惯用语不适合生产代码。 (但它看起来像是一个在开发过程中快速获取事物计时的好工具。)
Guava project and the 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");
}