当前位置: 首页 > 知识库问答 >
问题:

处理时间度量的最佳方法?[副本]

魏航
2023-03-14

我的目标是编写一个用于测量方法执行或事务时间以及处理测量的框架,即存储、分析等事务可能包括对外部系统的调用,并同步或异步等待结果。

已经有一些问题围绕着这个话题,比如

  • “如何对方法的执行进行计时”
  • “度量Java方法的执行时间”
  • “System.CurrentTimeMillis vs System.NanoTime”

所有的答案都可以归结为三种花时间的方法

  • System.CurrentTimeMillis()
  • System.nanoTime()
  • instant.now()duration(自Java八号以来)

我知道,所有这些都有一些暗示

这种方法的结果取决于平台。在Linux上,分辨率为1ms,在Windows上,分辨率为10ms(单核)~15ms(多核)。所以它可以用来测量大型运行操作或短期运行操作的多次执行。

你得到了一个高分辨率的时间测量,以纳秒的精度(但不一定是纳秒的精确度),292年后你得到了一个溢出(我可以忍受)。

自Java 8号以来,有了新的时间API。instant有一个秒和一个纳秒字段,因此它在对象引用的顶部使用两个长值(对于duration)。您还可以获得纳秒精度,这取决于基础时钟(请参见“Java 8 instant.now()具有纳秒分辨率?”)。实例化是通过调用instant.now()来完成的,该instant.now()映射到正常系统时钟的System.currentTimeMillis()

鉴于这些事实,很明显,最佳精度只能通过system.nanotime()来实现,但我的问题更多地针对处理一般度量的最佳实践,这不仅包括度量的采取,还包括度量的处理。

>

  • 即时和持续时间提供了最好的API支持(计算、比较等),但在标准情况下具有依赖于OS的精度,并且内存和创建度量(对象构造、更深的调用堆栈)的开销更大

    System.nanoTime()和System.CurrentTimeMillis()具有不同的精度级别,但仅具有基本的“API”支持(长时间的数学运算),但获得的速度更快,内存中的存储空间更小。

    那么最好的方法是什么呢?有没有我没想到的暗示?还有其他选择吗?

  • 共有1个答案

    谯志诚
    2023-03-14

    你把太多的注意力放在精度的不重要的细节上了。如果您想要测量/剖析某些操作的执行情况,您必须确保这些操作运行的时间足够长,以使测量不受一次性工件、线程调度定时的小差异、垃圾收集或热点优化的影响。在大多数情况下,如果差异变得小于毫秒尺度,那么它们对从中得出结论是没有用的。

    更重要的方面是工具是否是为您的任务设计的。System.CurrentTimeMillis()和所有其他基于挂钟的API,无论它们是否基于CurrentTimeMillis(),都是为了给您提供一个与地球自转及其围绕太阳的路径同步的时钟,这会给它带来闰秒和其他校正措施的负担,更不用说您的计算机时钟可能与挂钟不同步,并得到校正,例如通过NTP更新,在最坏的情况下,当您试图测量您的已用时间时跳到正确位置,甚至倒退。

    与此相反,system.nanotime()设计为测量经过的时间(这正是您想要做的事情),而不是其他事情。由于它的返回值有一个未指定的起源,甚至可能是负值,因此只有通过该方法返回的两个值之间的差异才有意义。您甚至可以在文档中找到这一点:

    只有在计算在Java虚拟机的同一实例中获得的两个这样的值之间的差值时,该方法返回的值才有意义。

    因此,当您想要测量和处理方法执行或事务的经过时间时,System.nanoTime()是一种可行的方法。诚然,它只提供了一个裸露的long值,但不清楚您需要什么样的API支持。由于时间点在这里是不相关的,甚至会分散注意力,所以您将只有一个持续时间,您可以将其转换为其他时间单位,或者,如果您想使用新的时间API,您可以使用duration.ofnanos(long)创建一个duration对象,允许您添加和减去持续时间值并对它们进行比较,但是您不能再做更多的事情了。你不能把它们和挂钟或日历的持续时间混在一起…

    最后要说明的是,文档中关于限制的内容有点不准确。如果您正在计算system.nanotime()返回的两个值之间的差值,那么数值溢出本身并不坏。由于计数器的起源未指定,因此操作的起始值可能接近long.max_value,而结束值接近long.min_value,因为JVM的计数器有溢出。在这种情况下,计算差值将导致另一个溢出,为差值产生正确的值。但是,如果您将该差异存储在有符号的long中,它最多可以保持2×ns的时间,将差异限制在最大292年,但是如果您将其视为无符号的long,例如通过long.compareunsignedlong.tounsignedString,您甚至可以处理2纳秒的持续时间,换句话说,如果您的计算机不介于两者之间,那么您可以用这种方法测量多达584年的经过时间…

     类似资料:
    • 什么是最好的方法来衡量Android代码段的执行时间? 我有一段前后的代码,我想用时间戳来确定它的执行时间(例如,中的一段,以及活动方法中的另一段)。 我已经试过了。toMillies(false),但它只会向我返回秒数(最后是常量)。我还尝试了两个java函数:和。第一个返回纪元时间的毫秒,第二个不返回。 测量执行时间并获得良好精度的最佳方法是什么?

    • 目前,我的应用程序的某些部分在将大量数据加载到报告表时遇到了速度问题。报告表中的数据是从多个表中提取的,并运行一些复杂的查询,但这是必需的。 除了优化代码,我的问题是,您个人如何处理需要向用户显示的大量数据,最佳实践是什么? 目前我正在处理所有的数据,然后通过javascript库生成数据表。 我知道的事情: 用户不需要一次看到所有数据 用户需要能够搜索所有数据 用户需要能够过滤数据 最好的方法真

    • 问题内容: 每次我需要使用Java中的日期和/或时标时,我总是觉得自己做错了事,花了无尽的时间试图找到使用API​​的更好方法,而不必编写自己的Date and Time实用程序类。这是我刚遇到的一些烦人的事情: 从0开始的月份。我意识到最佳实践是使用Calendar.SEPTEMBER而不是8,但是令人讨厌的是8代表9月而不是8月。 获取没有时间戳的日期。我一直需要将日期的时间戳部分清零的实用程

    • 问题内容: 我有一个方法可以执行一些超时任务。我使用ExecutorServer.submit()获取Future对象,然后使用超时调用future.get()。这工作正常,但是我的问题是处理可能由我的任务引发的检查异常的最佳方法。以下代码可以正常工作,并保留检查的异常,但是如果方法签名中的检查的异常列表发生更改,则显得非常笨拙且容易中断。 对于如何解决这个问题,有任何的建议吗?我需要以Java

    • 问题内容: 当您在Android应用中处理Firebase数据(读,写…)时,您需要获取Firebase引用才能进行数据处理。 由于Firebase引用是一棵JSON树,因此,如果您指向树的根,则可以随时访问子级,而无论深度如何。 问题:从内存和延迟角度来看,在代码中处理此引用的最佳方法是什么? 根 C1 C10 C11 C2 C21 1 /在应用程序的根目录中创建静态Firebase引用。 2

    • 问题内容: 我必须在php中解析大型XML文件,其中之一是6.5 MB,它们甚至可能更大。如我所读,SimpleXML扩展将整个文件加载到一个对象中,这可能不是很有效。以您的经验,最好的方法是什么? 问题答案: 对于大文件,您将要使用SAX解析器而不是DOM解析器。 使用DOM解析器,它将读取整个文件并将其加载到内存中的对象树中。使用SAX解析器,它将顺序读取文件并调用用户定义的回调函数来处理数据