在python中测量经过的时间
Posted
技术标签:
【中文标题】在python中测量经过的时间【英文标题】:Measuring elapsed time in python 【发布时间】:2011-11-17 07:26:17 【问题描述】:有没有一种简单的方法/模块可以正确测量python中的经过时间?我知道我可以简单地调用time.time()
两次并获取差额,但是如果更改系统时间会产生错误的结果。诚然,这种情况并不经常发生,但它确实表明我测量的是错误的东西。
使用time.time()
来衡量持续时间是令人难以置信的迂回考虑。您获取两个绝对时间测量值的差异,这两个绝对时间测量值依次由持续时间测量(由计时器执行)和已知绝对时间(手动或通过 ntp 设置)构成,您根本不感兴趣。
那么,有没有办法直接查询这个“定时器时间”呢?我想它可以表示为没有有意义的绝对表示的毫秒或微秒值(因此不需要用系统时间进行调整)。环顾四周,这似乎正是 System.nanoTime()
在 Java 中所做的,但我没有找到相应的 Python 函数,尽管它应该(硬件技术上)比 time.time()
更容易提供。
编辑:为避免混淆并解决以下答案:这与 DST 更改无关,我也不想要 CPU 时间 - 我想要经过的物理时间。它不需要非常细粒度,甚至不需要特别准确。它只是不应该给我负持续时间,或者持续时间相差几个数量级(高于粒度),只是因为有人决定将系统时钟设置为不同的值。以下是 Python 文档对 'time.time()' 的评价:
"While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls"
这正是我想要避免的,因为它会导致奇怪的事情,比如时间计算中的负值。我现在可以解决这个问题,但我相信在可行的情况下学习使用正确的解决方案是个好主意,因为有一天这些杂物会卷土重来。
Edit2:一些研究表明,您可以像我在 Windows 中使用 GetTickCount64() 一样获得与系统时间无关的测量值,在 Linux 下,您可以在 times() 的返回值中获得它。但是,我仍然找不到在 Python 中提供此功能的模块。
【问题讨论】:
如果你想对某些东西进行基准测试,你应该使用timeit
。
相关:How do I get monotonic time durations in python?
您可能会遇到Microsoft Minute。
【参考方案1】:
要测量经过的 CPU 时间,请查看 time.clock()。这相当于 Linux 的 times() 用户时间字段。
对于基准测试,请使用timeit。
如果平台支持,datetime module、which is part of Python 2.3+ 也有微秒时间。
例子:
>>> import datetime as dt
>>> n1=dt.datetime.now()
>>> n2=dt.datetime.now()
>>> (n2-n1).microseconds
678521
>>> (n2.microsecond-n1.microsecond)/1e6
0.678521
ie, it took me .678521 seconds to type the second n2= line -- slow
>>> n1.resolution
datetime.timedelta(0, 0, 1)
1/1e6 resolution is claimed.
如果您担心系统时间更改(从 DS -> ST),只需检查 datetime 返回的对象。据推测,系统时间可能会根据 NTP 参考调整进行小幅调整。 This should be slewed,更正是 applied gradually,但 ntp 同步节拍可能对非常小的(毫秒或微秒)时间参考产生影响。
如果您想要该分辨率的内容,也可以参考Alex Martelli's C function。我不会走得太远去重新发明***。准确的时间是基本的,大多数现代操作系统都做得很好。
编辑
根据您的说明,听起来您需要简单检查一下系统时钟是否已更改。只需与友好的本地 ntp 服务器进行比较:
import socket
import struct
import time
ntp="pool.ntp.org" # or whatever ntp server you have handy
client = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
data = '\x1b' + 47 * '\0'
client.sendto( data, ( ntp, 123 ))
data, address = client.recvfrom( 1024 )
if data:
print 'Response received from:', address
t = struct.unpack( '!12I', data )[10]
t -= 2208988800L #seconds since Epoch
print '\tTime=%s' % time.ctime(t)
NTP 在 Internet 上精确到毫秒,并具有 2-32 秒(233 皮秒)的分辨率表示分辨率。应该够好吗?
注意 NTP 64 位数据结构 will overflow in 2036 and every 136 years thereafter -- 如果你真的想要一个健壮的解决方案,最好检查溢出...
【讨论】:
+1 用于回转信息,可缓解问题。但是,我不追求更高的粒度。事实上,在我当前的应用程序中,几秒钟就可以了。 我不认为 NTP 服务器查询是一个优雅的解决方案。毕竟,基本上每台 PC 都有专门的硬件来测量我想要构建的内容,并且可以通过 Windows 和 Linux 上的系统功能进行查询 - 请参阅上面的新编辑。 @Medo42:您不需要对每个计时器实例进行 ntp 调用;仅当time.time()
返回负数或意外情况时。 Pyson's 与time.clock()
比较的方法有优点。您可以使用类似的东西来触发何时与外部来源进行比较。就我个人而言,操作系统时间对于我来说足以满足毫秒级以上的时间要求。使用硬件计时器有其自身的准确性问题。
请注意,该示例在说明“键入第二个 n2= 行需要 0.678521 秒”时具有误导性。 'microseconds' 方法只返回时间差的微秒部分。调用“秒”返回时间的秒部分。总时间实际上是 (n2-n1).seconds + (n2-n1).microseconds/1e6。或者,可以调用 (n2-n1).total_seconds() 将这两个部分结合起来。【参考方案2】:
您似乎正在寻找的是monotonic timer。 monotonic time reference 不会跳转或后退。
基于 Python 的 OS 参考,已经多次尝试为 Python 实现跨平台单调时钟。 (Windows、POSIX 和 BSD 完全不同)请参阅 this SO post 中的讨论和单调时间的一些尝试。
大多数情况下,您可以只使用 os.times():
os.times()
返回一个 5 元组的浮点数,表示 累计(处理器或其他)时间,以秒为单位。这些项目是: 用户时间,系统时间,儿童用户时间,儿童系统时间, 并且从过去的固定点开始按该顺序经过的实时时间。 请参阅 Unix 手册页 times(2) 或相应的 Windows 平台 API 文档。在 Windows 上,只有前两项是 填充,其他为零。
可用性:Unix、Windows
但这并不能填充 Windows 上所需的经过的实时时间(第五个元组)。
如果您需要 Windows 支持,请考虑 ctypes
,您可以直接调用 GetTickCount64(),就像在 this recipe 中所做的那样。
【讨论】:
我想知道为什么没有人提议在 Windows 上将第 5 个元组值添加到 os.times 中?似乎应该是可能的,因为没有指定参考点。 @Mark Ransome:不是 Winoze 人,但可能是因为GetTickCount64()
之类的东西或相同的 32 版本不在 cPython 基线假定的核心 Windows API 中?即,该平台上的传统支持?别的不知道。单调时间参考是一个有用的功能。【参考方案3】:
Python 3.3 在标准库中添加了一个monotonic timer,这正是我想要的。感谢 Paddy3118 在"How do I get monotonic time durations in python?" 中指出这一点。
【讨论】:
【参考方案4】:>>> import datetime
>>> t1=datetime.datetime.utcnow()
>>> t2=datetime.datetime.utcnow()
>>> t2-t1
datetime.timedelta(0, 8, 600000)
使用 UTC 可以避免那些由于夏令时而导致时钟偏移的尴尬时期。
至于使用替代方法而不是减去两个时钟,请注意操作系统确实包含一个时钟,该时钟是从 PC 中的硬件时钟初始化的。现代操作系统实现还将使该时钟与某些官方来源保持同步,以使其不会漂移。这比 PC 可能运行的任何间隔计时器都准确得多。
【讨论】:
更准确 - 是的,从长远来看。尽管在调整它的那一刻,这个时钟时间可能会表现得很奇怪(除非调整被改变,如drawk的回答中所述)。我不需要长时间的高精度,但我需要可靠的短期测量,不会因为有人决定手动更改系统时间而给出负数或太大的间隔 - 这有时确实会发生。 tElapsed = datetime.timedelta.total_seconds(t2-t1) 在 Python 3.6 中【参考方案5】:from datetime import datetime
start = datetime.now()
print 'hello'
end = datetime.now()
delta = end-start
print type(delta)
<type 'datetime.timedelta'>
import datetime
help(datetime.timedelta)
...elapsed seconds and microseconds...
【讨论】:
【参考方案6】:您在编辑中陈述的示例函数是两个完全不同的东西:
-
Linux times() 返回进程时间(以 CPU 毫秒为单位)。 Python 的等价物是 time.clock() 或
os.times()
。
Windows GetTickCount64() 返回系统正常运行时间。
虽然有两种不同的功能,但都(可能)可用于通过这些方法显示出现“打嗝”的系统时钟:
第一:
time.time()
可以占用系统时间,time.clock()
可以占用 CPU 时间。由于挂钟时间总是大于或等于 CPU 时间,因此如果两个 time.time()
读数之间的间隔小于成对的 time.clock()
检查读数,则丢弃任何测量。
例子:
t1=time.time()
t1check=time.clock()
# your timed event...
t2=time.time()
t2check=time.clock()
if t2-t1 < t2check - t1check:
print "Things are rotten in Denmark"
# discard that sample
else:
# do what you do with t2 - t1...
第二:
如果您担心系统时钟,那么获得系统正常运行时间也很有希望,因为在大多数情况下,用户重置不会重置正常运行时间滴答计数。 (我知道...)
现在更难的问题是:以独立于平台的方式获得系统正常运行时间——尤其是在不产生新外壳的情况下——以亚秒级的精度。嗯……
可能最好的选择是psutil。 Browsing the source,他们使用 uptime = GetTickCount() / 1000.00f;
用于 Windows,sysctl "kern.boottime"
用于 BSD / OS X 等。不幸的是,这些都是 1 秒分辨率。
【讨论】:
一开始我也对 times() 感到困惑,但请阅读您自己的链接手册(特别是说“返回值”的部分。)该函数可用于查找处理时间,即填充到提供的结构中,但它返回一个独立于系统时钟的时间度量。 挂钟时间总是大于CPU时间是真的吗?我相信这仅适用于单核系统。【参考方案7】:在 Python 3.3+ 中使用 time.monotonic 后,我发现它在 Mac 上运行良好,永远不会倒退。在使用 GetTickCount64() 的 Windows 上,它很少会后退大量(出于我的程序超过 5.0 的目的)添加包装器可以防止单调后退:
with a_lock:
original_value = time.monotonic()
if original_value < last_value:
# You can post a metric here to monitor frequency and size of backward jumps
offset = last_value - original_value
last_value = original_value
return offset + original_value
倒退的频率如何?在数以百万计的机器上,可能会在数天之内发生几次,然后再一次,仅在 Windows 上。抱歉,我没有跟踪哪些版本的 Windows。如果人们愿意,我可以稍后更新。
【讨论】:
以上是关于在python中测量经过的时间的主要内容,如果未能解决你的问题,请参考以下文章