如何在 Java 中以微秒精度测量时间?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/503877/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I measure time with microsecond precision in Java?
提问by
I saw on the Internet that I was supposed to use System.nanoTime()
but that doesn't work for me - it gives me the time with milliseconds precision. I just need the microseconds before and after my function executes so that I know how long it takes. I'm using Windows XP.
我在互联网上看到我应该使用,System.nanoTime()
但这对我不起作用 - 它给了我毫秒精度的时间。我只需要函数执行前后的微秒,以便我知道需要多长时间。我正在使用 Windows XP。
Basically, I have this code that, for example, does 1 million up to 10 millions of insertions in a java linked list. The problem is that I can't measure the precision right; sometimes it takes less time to insert everything in the smaller list.
基本上,我有这段代码,例如,在 java 链表中执行 100 万到 1000 万次插入。问题是我无法正确测量精度;有时在较小的列表中插入所有内容所需的时间更少。
Here's an example:
下面是一个例子:
class test
{
public static void main(String args[])
{
for(int k=1000000; k<=10000000; k+=1000000)
{
System.out.println(k);
LinkedList<Integer> aux = new LinkedList<Integer>();
//need something here to see the start time
for(int i=0; i<k; i++)
aux.addFirst(10000);
//need something here to see the end time
//print here the difference between both times
}
}
}
I did this many times - there was an exterior loop doing it 20 times for each k - but the result aren't good. Sometimes it takes less time to to make 10 million insertions than 1 million, because I'm not getting the correct measured time with what I'm using now (System.nanoTime())
我做了很多次 - 有一个外部循环为每个 k 执行 20 次 - 但结果并不好。有时,进行 1000 万次插入所需的时间比 100 万次要少,因为我现在使用的内容没有得到正确的测量时间 (System.nanoTime())
Edit 2: Yes, I'm using the Sun JVM.
编辑 2:是的,我使用的是 Sun JVM。
Edit 3: I may have done something wrong in the code, I'll see if changing it does what I want.
编辑 3:我可能在代码中做错了什么,我会看看更改它是否符合我的要求。
Edit 4: My mistake, it seems System.nanoTime() works. Phew.
编辑 4:我的错误,似乎 System.nanoTime() 有效。呼。
回答by Jon Skeet
It's not clear to me exactly what you're benchmarking, but in general, any test which takes sucha short amount of time to run, that accuracy lower than 50 ms is relevant, is going to be veryprone to other disturbances.
我不清楚你到底在做什么基准测试,但一般来说,任何运行时间如此短、精度低于 50 毫秒的测试都是相关的,将很容易受到其他干扰。
I generally try to make benchmarks run for at least 10 seconds. The framework I'm writing at the moment will guess how many iterations to run so that it will take 30 seconds. That means you won't get radicallydifferent results just because some other process stole the CPU for a few milliseconds.
我通常尝试使基准测试运行至少 10 秒。我目前正在编写的框架将猜测要运行多少次迭代,以便需要 30 秒。这意味着您不会仅仅因为其他一些进程在几毫秒内偷走了 CPU 就得到完全不同的结果。
Running for longer is almost always a better approachthan trying to measure with finer-grained accuracy.
与尝试以更细粒度的精度进行测量相比,运行更长时间几乎总是一种更好的方法。
回答by Sarel Botha
That's weird. System.nanoTime() is supposed to work. Are you using the Sun JVM?
这很奇怪。System.nanoTime() 应该可以工作。您在使用 Sun JVM 吗?
Can you just repeat your operation 1000 times and divide the time by 1000 to find out what you need to know?
你能简单地重复你的操作 1000 次并将时间除以 1000 来找出你需要知道的吗?
回答by Tiago
You have to repeat the tests thousands of times. There are lots of things happening that will influence your measurements, like garbage collection, I/O, swap in/out, the size of the ready-queue threads, etc.
您必须重复测试数千次。有很多事情会影响你的测量,比如垃圾收集、I/O、换入/换出、就绪队列线程的大小等。
回答by Zach Scrivena
My guess is that since System.nanoTime()
uses the "most precise available system timer" which apparently only has millisecond-precision on your system, you can't get anything better.
我的猜测是,由于System.nanoTime()
使用“最精确的可用系统计时器”,它在您的系统上显然只有毫秒精度,因此您无法获得更好的结果。
回答by starblue
It may be the case that the underlying OS doesn't provide timers with nanosecond precision.
可能是底层操作系统不提供具有纳秒精度的计时器的情况。
There is also an older post.
还有一个较旧的帖子。
回答by Mnementh
Such a benchmark that relies on short time-interval gives you unreliable results. You will always get different results, because of external factors like I/O, Swapping, Process Switches, Caches, Garbage Collection etc. Additionally the JVM optimizes your calls, so it's likely that the first measured things are going slower than later call. The JVM starts more and more to optimize the commands you execute.
这种依赖于短时间间隔的基准测试会给您带来不可靠的结果。由于 I/O、交换、进程切换、缓存、垃圾收集等外部因素,您总是会得到不同的结果。此外,JVM 会优化您的调用,因此很可能第一个测量的东西比后面的调用慢。JVM 会越来越多地启动以优化您执行的命令。
Additionally the method like System.nanoTime() is dependent on the timers of the underlying system. They may (and most likely will) not have the granularity to measure in that accuracy. To cite the API:
此外,像 System.nanoTime() 这样的方法依赖于底层系统的计时器。他们可能(并且很可能不会)具有衡量该准确性的粒度。引用API:
This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change.
此方法提供纳秒精度,但不一定提供纳秒精度。不保证值更改的频率。
To really measure with high precision you need to access an external timing hardware with guaranteed precision.
要真正以高精度进行测量,您需要访问具有保证精度的外部计时硬件。
To make your benchmark more stable you need to execute it more than once and to measure bigger time-intervals than only milliseconds.
为了使您的基准更稳定,您需要多次执行它并测量比毫秒更大的时间间隔。
回答by Peter Lawrey
System.nanoTime()
uses a counter in the CPU and is usually accurate to about 1 micro-second on Windows XP and Linux.
System.nanoTime()
在 CPU 中使用计数器,在 Windows XP 和 Linux 上通常精确到大约 1 微秒。
Note: Windows XP is often less accurate on multi-cpu machines as it doesn't compensate for different CPUs having different counters. Linux does. Note 2: It will drift relative to the System.currentTimeMillis() as it is based on the accuracy of the clock for your CPU (which doesn't need to be so accurate over a period of time), rather than the clock you have for getting the time.(which drifts less per day, but has less granularity)
注意:Windows XP 在多 CPU 机器上通常不太准确,因为它不能补偿具有不同计数器的不同 CPU。Linux 确实如此。注 2:它会相对于 System.currentTimeMillis() 漂移,因为它基于 CPU 时钟的准确性(在一段时间内不需要如此准确),而不是您拥有的时钟获取时间。(每天漂移较少,但粒度较小)
In your benchmark you are basically testing the speed at which you can create new objects. Not surprisingly your results will vary dramatically based on your GC settings and how recently a GC has been performed.
在您的基准测试中,您基本上是在测试创建新对象的速度。毫不奇怪,根据您的 GC 设置和最近执行 GC 的时间,您的结果会发生巨大变化。
Try running your tests with the following options and you should see very different results.
尝试使用以下选项运行测试,您应该会看到非常不同的结果。
-verbosegc -XX:NewSize=128m -mx256m
回答by marcospereira
If you want a reliable result, use a profiler. I suggest VisualVM, which is easy to install and is bundled with the JDK starting from version 1.6.0_07.
如果您想要可靠的结果,请使用分析器。我建议使用VisualVM,它易于安装并且从 1.6.0_07 版开始与 JDK 捆绑在一起。
It is an easy to use visual tool that integrates several commandline JDK tools and lightweight profiling capabilities.
它是一个易于使用的可视化工具,集成了多个命令行 JDK 工具和轻量级分析功能。
回答by DaveFar
Yes, the accuracy and precision of System.nanoTime is usually much better than System.currentTimeMillis, but without guarantee: it can become just as bad in the worst case.
是的,System.nanoTime 的准确性和精确度通常比 System.currentTimeMillis 好得多,但不能保证:在最坏的情况下它可能变得同样糟糕。
ThreadMXBean.getCurrentThreadCpuTime tends to yield smaller times, but its resolution is unclear, and it has further disadvantages (do you really want the CPU time?, platform dependent semantics, supported on your platform?).
ThreadMXBean.getCurrentThreadCpuTime 往往会产生更小的时间,但其分辨率尚不清楚,并且还有其他缺点(您真的想要 CPU 时间吗?平台相关语义,您的平台支持吗?)。
Measuring the time with all three techniques also has some cost, i.e. requires time itself, which can distort the measurements. The costs are highly platform dependent, but often cost(System.currentTimeMillis) << cost(System.nanoTime) << cost(ThreadMXBean.getCurrentThreadCpuTime).
使用所有三种技术测量时间也有一定的成本,即需要时间本身,这可能会使测量结果失真。成本高度依赖于平台,但通常成本(System.currentTimeMillis) << cost(System.nanoTime) << cost(ThreadMXBean.getCurrentThreadCpuTime)。
About micro benchmarking in general, see
关于一般的微基准测试,请参阅
回答by keisar
a "quick and dirty" solution that I eventually went with:
我最终采用的“快速而肮脏”的解决方案:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
UPDATE:
更新:
I originally went with System.nanoTime but then I found out it should only be used for elapsed time, I eventually changed my code to work with milliseconds or at some places use:
我最初使用 System.nanoTime 但后来我发现它应该只用于经过的时间,我最终更改了我的代码以使用毫秒或在某些地方使用:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
but this will just add zeros at the end of the value (micros = millis * 1000)
但这只会在值的末尾添加零(微 = 毫秒 * 1000)
Left this answer here as a "warning sign" in case someone else thinks of nanoTime :)
将此答案留在这里作为“警告标志”,以防其他人想到 nanoTime :)