5

它可以很方便地为代码执行计时,这样您就知道需要多长时间。但是,我发现这是草率完成的常见方式,因为它应该具有相同的缩进,这使得阅读实际计时的内容变得更加困难。

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

3 回答 3

3

你的解决方案很好。

一种表达较少的方法是将代码包装在 lambda 中进行计时。

public void timeCode(Runnable code) {
    ...
    try {
        code.run();
    } catch ...
    }
    ...
}

timeCode(() -> { ...code to time... });

您可能希望捕获已检查的异常并将它们传递给某个运行时异常或其他什么。

于 2018-10-23T11:11:41.400 回答
1

你的方法很好。我们专业地使用类似的东西,但用 C# 编写。

我可能会添加的一件事是适当的日志记录支持,以便您可以切换这些性能数字,或者将它们置于调试或信息级别。

我将考虑的其他改进是创建一些静态应用程序状态(滥用线程本地),以便您可以嵌套这些部分,并进行汇总细分。

请参阅https://github.com/aikar/minecraft-timings了解为我的世界改装(用 java 编写)执行此操作的库。

于 2018-10-23T11:03:45.897 回答
1

我认为问题文本中建议的解决方案过于间接且不习惯,不适合生产代码。(但它看起来像是一个在开发过程中快速获取时间的简洁工具。)

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");
}
于 2018-11-29T14:43:33.467 回答