在Python中测量经过时间

51 投票
8 回答
82758 浏览
提问于 2025-04-17 02:18

有没有简单的方法或者模块可以在Python中正确测量经过的时间?我知道我可以简单地调用time.time()两次,然后计算它们的差值,但如果系统时间被更改,这样的结果就会不准确。虽然这种情况不常发生,但这说明我测量的东西是错误的。

time.time()来测量时间间隔其实是个很绕的方式。你是通过两个绝对时间的测量值来计算差值,而这两个绝对时间又是由计时器的持续时间测量和手动设置的绝对时间(或者通过网络时间协议设置的)构成的,其实你根本不关心这些。

那么,有没有办法直接查询这种“计时器时间”呢?我想它可以表示为毫秒或微秒的值,这种值没有实际的绝对意义(因此不需要和系统时间进行调整)。我查了一下,发现这正是Java中的System.nanoTime()所做的,但我没有找到Python中对应的函数,尽管从硬件技术上讲,提供这个功能应该比time.time()更简单。

补充说明:为了避免混淆并回应下面的回答:这不是关于夏令时的变化,我也不想要CPU时间——我想要的是经过的实际时间。它不需要非常精确,也不需要特别细致。只要不会给我负的时间间隔,或者因为有人把系统时钟设置成其他值而导致的几倍于实际的时间间隔就可以了。以下是Python文档对'time.time()'的说明:

“虽然这个函数通常返回不减少的值,但如果在两次调用之间系统时钟被调回,它可能会返回一个比之前调用更低的值”

这正是我想要避免的,因为这可能导致时间计算中出现负值等奇怪的情况。目前我可以找到解决办法,但我认为学习使用合适的解决方案是个好主意,因为临时的解决方案总有一天会反噬你。

补充说明2:一些研究表明,在Windows中可以通过使用GetTickCount64()获得我想要的独立于系统时间的测量值,而在Linux中可以通过times()的返回值获得。不过,我仍然找不到提供这种功能的Python模块。

8 个回答

12

你似乎在寻找一种叫做单调计时器的东西。单调时间参考不会跳跃或倒退。

为了在不同操作系统上实现一个跨平台的单调时钟,Python社区做过几次尝试,因为Windows、POSIX和BSD之间差别很大。你可以查看这篇SO帖子中的讨论和一些尝试。

通常,你可以直接使用os.times():

os.times()

这个函数会返回一个包含五个浮点数的元组,表示累积的(处理器或其他)时间,单位是秒。具体内容包括:用户时间、系统时间、子进程的用户时间、子进程的系统时间,以及自过去某个固定时间点以来的实际经过时间,顺序是这样的。你可以查看Unix手册页times(2)或相应的Windows平台API文档。在Windows上,只有前两个值会被填充,其他的都是零。

可用性:Unix, Windows

不过,这个方法在Windows上无法提供所需的实际经过时间(第五个值)。

如果你需要Windows支持,可以考虑使用ctypes,这样你可以直接调用GetTickCount64(),就像在这个示例中所做的那样。

27

如果你想测量CPU运行的时间,可以看看 time.clock()。这个函数和Linux系统里的 times() 中的用户时间字段是一样的。

如果你想做性能测试,可以使用 timeit

还有一个 datetime模块,这个模块是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(网络时间协议)的调整而有小幅度的变化。 这个调整应该是逐渐进行的,而且修正也是 逐步应用的,不过NTP同步的频率可能会对非常小的时间(毫秒或微秒)产生影响。

如果你需要更高精度的时间,可以参考 Alex Martelli的C语言函数。我建议不要过于复杂,准确的时间是基础,大多数现代操作系统在这方面做得都不错。

编辑

根据你的说明,听起来你需要一个简单的方法来检查系统时钟是否发生了变化。你可以和一个本地的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在互联网上的准确度可以达到毫秒级,表示的分辨率是2的负32次方秒(233皮秒)。这样应该足够用了吧?

要注意的是,NTP的64位数据结构 在2036年会溢出,以后每136年也会溢出——如果你真的想要一个稳健的解决方案,最好检查一下是否会溢出……

2

你可以使用Python标准库中的perf_counter函数来计时:

from datetime import timedelta
from time import perf_counter

startTime = perf_counter()
CallYourFunc()
finishedTime = perf_counter()
duration = timedelta(seconds=(finishedTime - startTime))

撰写回答