【问题标题】:How do I get monotonic time durations in python?如何在 python 中获得单调持续时间?
【发布时间】:2010-11-15 09:33:10
【问题描述】:

我想记录某件事在实时墙上的时间。目前我正在这样做:

startTime = time.time()
someSQLOrSomething()
print "That took %.3f seconds" % (time.time() - startTime)

但如果在 SQL 查询(或其他任何查询)运行时调整时间,这将失败(产生不正确的结果)。

我不想仅仅对其进行基准测试。我想将其记录在实时应用程序中,以便查看实时系统的趋势。

我想要类似 clock_gettime(CLOCK_MONOTONIC,...) 的东西,但在 Python 中。而且最好不必编写调用clock_gettime()的C模块。

【问题讨论】:

  • 好吧,我真的不知道它实际调整的频率。我运行NTP。但是有了单调时钟,我就不必遇到诸如 Oracle RAC 错误之类的问题,如果时间向后设置,它会重新启动系统。除了小的 NTP 调整外,还有可以前后移动的闰秒。
  • S.Lott:不正确。 “闰秒是正或负的一秒调整 [...]”。抬头看是微不足道的。这是维基百科上“闰秒”文章的第一句话。因此,当添加闰秒时,NTP 将向后重新调整您的系统时间(因为您的系统速度很快。它没有计算 23:59:60),这意味着基于 time.time() 的测量可能是负数。相信我,由于我去年提到的错误,许多 Oracle 服务器重新启动。我只是以 Oracle 为例,有些程序无法处理时间调整。
  • 我不知道为什么(未打补丁的)Oracle 10 会这样做。确实如此,甲骨文(该公司)证实了这一点。
  • 只是想在这里添加一个我们遇到的用例的评论。在我们由多个 vmware 系统组成的设置中,我们注意到来宾 vm 中确实经常发生时间“调整”,尤其是在主机的平均负载情况下。高。这会导致 supervisord 之类的东西似乎依赖于 time.time() 崩溃,从而导致它启动的进程孤立。我们已通过应用补丁 ^ 修复 ^ 这个问题 - github.com/Supervisor/supervisor/pull/468
  • @Thomas:理论上,可能会有负闰秒。实际上,所有闰秒都是正数。见The leap second: its history and possible future

标签: python linux benchmarking clock


【解决方案1】:

这个函数很简单,你可以使用 ctypes 来访问它:

#!/usr/bin/env python

__all__ = ["monotonic_time"]

import ctypes, os

CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h>

class timespec(ctypes.Structure):
    _fields_ = [
        ('tv_sec', ctypes.c_long),
        ('tv_nsec', ctypes.c_long)
    ]

librt = ctypes.CDLL('librt.so.1', use_errno=True)
clock_gettime = librt.clock_gettime
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]

def monotonic_time():
    t = timespec()
    if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0:
        errno_ = ctypes.get_errno()
        raise OSError(errno_, os.strerror(errno_))
    return t.tv_sec + t.tv_nsec * 1e-9

if __name__ == "__main__":
    print monotonic_time()

【讨论】:

  • 哇。删除“自我”。它工作得很好。非常令人印象深刻。它需要 ctypes,它是 Python 2.4 的附加组件,但它会做得很好。谢谢。
  • 哦,CLOCK_MONOTONIC 在 FreeBSD 上似乎是 4,在 Linux 上似乎是 1。
  • 不错的解决方案。你有什么理由使用 ctypes.pointer 而不是 ctypes.byref?
  • 使用 CLOCK_MONOTONIC_RAW==4(自 Linux 2.6.28 起;Linux 特定)以避免 NTP 调整。
  • 感谢 @ArminRonacher 的回答,我已将其合并到我在此处发布的 Windows/Linux 兼容模块中:stackoverflow.com/a/38319607/4561887
【解决方案2】:

正如this question 中指出的那样,避免在 Linux 上重新调整 NTP 需要 CLOCK_MONOTONIC_RAW。在 Linux 上定义为 4(自 2.6.28 起)。

在 Python 的 C 头文件中可移植地获取正确的常量#defined 是很棘手的;有 h2py,但这并不能真正帮助您在运行时获得价值。

【讨论】:

  • 我认为选择的答案不正确并且没有解释跳跃,请参阅my comment on it。 CLOCK_MONOTONIC 和 CLOCK_MONOTONIC_RAW 都是单调的,唯一不同的是前者使用 NTP 校正硬件时钟速度。
【解决方案3】:

现在,在 Python 3.3 中,您将使用 time.monotonic

【讨论】:

  • 在 CPython 中,我假设这在内部使用 CLOCK_MONOTONICnot CLOCK_MONOTONIC_RAW,后者甚至在 Python 3.3 中都不可用。
  • 如果我没看错文档,看来在 Python 3.3 中,您可以通过调用 time.clock_gettime(time.CLOCK_MONOTONIC_RAW) 获得 CLOCK_MONOTONIC_RAW,这非常棒,因此当您使用它来测量小时间间隔时,您永远不会得到网络通过 NTP(网络时间协议)调整更新时间时引入的错误。 Python 时间参考:docs.python.org/3/library/time.html#time.CLOCK_MONOTONIC_RAW。 time.clock(),由于它使用 QueryPerformanceCounter(),它已经具有微秒或更好的分辨率。
【解决方案4】:

time.monotonic() 可能有用:

返回单调时钟的值(以秒为单位),即不能倒退的时钟。时钟不受系统时钟更新的影响。返回值的参考点是未定义的,因此只有连续调用的结果之间的差异才有效。

【讨论】:

    【解决方案5】:

    这是我在 Python 2.7 中获得单调时间的方法:

    安装monotonic 包:

    pip install monotonic
    

    然后在 Python 中:

    import monotonic; mtime = monotonic.time.time #now mtime() can be used in place of time.time()
    t0 = mtime()
    #...do something
    elapsed = mtime()-t0 #gives correct elapsed time, even if system clock changed.
    

    编辑:在信任之前检查上述内容是否适用于您的目标操作系统。单调库似乎可以处理某些操作系统中的时钟变化,而不是其他操作系统。

    【讨论】:

    • 这不是单调的。如果在调用之间更改系统时钟,它会失败,就像调用time.time() 在 OSX 上测试一样。
    • @Gabriel 它在单个 Python 进程中工作;我已经对其进行了测试并构建了一个依赖它的机器人。我怀疑如果它对你不起作用,那是因为你重新启动了 Python,这样你就得到了一个新的 Python 进程。
    • 只要您不手动触摸时间/日期,或者操作系统不会自动触摸它,它就可以工作。
    • 嗯,你是对的;它似乎依赖于操作系统。在带有 Raspbian 的 Raspberry Pi 上更改系统时间肯定不会影响它,但在 Ubuntu 20 上它看起来确实如此,这与库的文档相反。令人失望。
    猜你喜欢
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    • 2018-06-21
    • 1970-01-01
    相关资源
    最近更新 更多