likes
comments
collection
share

Java 和 C 中 测量代码耗时 最佳实践

作者站长头像
站长
· 阅读数 2

在 Java 中测量时间

System.currentTimeMillis()

此方法返回当前距离 1970年1月1日(UTC,世界协调时)的毫秒值。虽然是返回的时间单位是毫秒,但是其返回的时间粒度取决于底层操作系统,可能会比毫秒要大。例如,许多操作系统以几十毫秒为单位来进行时间测量。

此处的时间颗粒度指的是此值多久改变一次。如果你在一个死循环中不断的打印此方法返回的毫秒值,有可能会发现打印的结果是不连续的。这就取决于底层操作系统的实现了。

对于不同的虚拟机实现,因为是基于物理时间,此方法也将会返回相同的结果。

使用 System.currentTimeMillis() 测试代码耗时:

long startTime = System.currentTimeMillis();
// ... the code being measured ...
long estimatedTime = System.currentTimeMillis() - startTime;

System.nanoTime()

相较于 System.currentTimeMillis(),这个方法返回的单位更精确:纳秒(0.001秒 = 1毫秒 = 100万纳秒)。此方法返回值一般仅用在测量耗时,因为其并不依赖于一个指定的时间点,而是一个随机的基准点。甚至这个基准的时间点有可能在未来,所以这个方法的返回值有可能是一个负的。但在同一个虚拟机中,这个随机的基准点至少是同一个。

此方法虽然返回的是纳秒,但是同 System.currentTimeMillis() 一样,此方法也是依赖于底层操作系统的实现,它可能并非每一个纳秒就会改变。但是能保证的是,其精度是要高于 System.currentTimeMillis() 的。

使用此方法时,注意此值可能溢出的情况。如果连续的时间大于 292 年的话,那么就可能会由于数字溢出导致无法正确测量时间。

使用 System.nanoTime() 测试代码耗时:

long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;

两种方法的区别

相较于 System.currentTimeMillis()System.nanoTime() 更加精确,但是它也更加重量级。System.currentTimeMillis() 方法在5、6个 CPU 时钟内即可返回结果,但是 System.nanoTime() 依赖于操作系统底层架构,可能需要需要100多个CPU时钟才能完成调用。

而且对于测量时间来说,System.nanoTime() 虽然返回的纳秒精度,但在大部分情况下,是不会精确到纳秒,很多时候使用还需要将其除以一些值。这使得其返回的低位部分意义不大。

在选择时,建议优先使用 System.currentTimeMillis(),毕竟毫秒能满足大部分情况。

在 C 中测量时间

在 C 语言中测量时间最好的方法就是使用 <time.h> 头文件中的 clock() 方法:

clock_t begin = clock();
/* here, do your time-consuming job */
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;

这个 clock() 的返回值虽然是一个 clock_t 类型,此值表示 CPU 的时钟数,将其除以 CLOCKS_PER_SEC(定义在 <time.h> 里的宏)可以转换为秒。虽然其单位是秒,但是其精度是远远大于秒的,具体也是依赖于底层系统实现。因此,此值可以用使用浮点数来表示,以获得更高精度的时间值,就像代码里的那样。

这个方法是标准 C 中提供的,因此不用担心移植的问题。在 C 中也有其他的方式来获取时间:

这两种方式都可行,但是相比于 clock() 方法来说,还是稍显复杂。在使用时,clock() 基本足够。

参考

System.currentTimeMillis vs System.nanoTime

Execution time of C program

How to measure time in milliseconds using ANSI C