Python中的高精度时钟

时间:2009-12-21 03:41:54

标签: python time

有没有办法在Python中以高精度测量时间---比一秒更精确?我怀疑是否有跨平台的方式来做到这一点;我对Unix上的高精度时间感兴趣,特别是在Sun SPARC机器上运行的Solaris。

timeit似乎能够进行高精度的时间测量,但我不想测量代码片段需要多长时间,而是想直接访问时间值。

14 个答案:

答案 0 :(得分:43)

标准time.time()函数提供亚秒级精度,但该精度因平台而异。对于Linux和Mac,精度为+- 1微秒或0.001毫秒。由于进程中断导致时钟实现问题,Windows上的Python使用+- 16毫秒的精度。如果您正在测量执行时间,timeit模块可以提供更高的分辨率。

>>> import time
>>> time.time()        #return seconds from epoch
1261367718.971009      

Python 3.7为time模块引入了提供更高分辨率的新功能:

>>> import time
>>> time.time_ns()
1530228533161016309
>>> time.time_ns() / (10 ** 9) # convert to floating-point seconds
1530228544.0792289

答案 1 :(得分:22)

Python努力为您的平台使用最精确的时间函数来实现time.time()

/* Implement floattime() for various platforms */

static double
floattime(void)
{
    /* There are three ways to get the time:
      (1) gettimeofday() -- resolution in microseconds
      (2) ftime() -- resolution in milliseconds
      (3) time() -- resolution in seconds
      In all cases the return value is a float in seconds.
      Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
      fail, so we fall back on ftime() or time().
      Note: clock resolution does not imply clock accuracy! */
#ifdef HAVE_GETTIMEOFDAY
    {
        struct timeval t;
#ifdef GETTIMEOFDAY_NO_TZ
        if (gettimeofday(&t) == 0)
            return (double)t.tv_sec + t.tv_usec*0.000001;
#else /* !GETTIMEOFDAY_NO_TZ */
        if (gettimeofday(&t, (struct timezone *)NULL) == 0)
            return (double)t.tv_sec + t.tv_usec*0.000001;
#endif /* !GETTIMEOFDAY_NO_TZ */
    }

#endif /* !HAVE_GETTIMEOFDAY */
    {
#if defined(HAVE_FTIME)
        struct timeb t;
        ftime(&t);
        return (double)t.time + (double)t.millitm * (double)0.001;
#else /* !HAVE_FTIME */
        time_t secs;
        time(&secs);
        return (double)secs;
#endif /* !HAVE_FTIME */
    }
}

(来自http://svn.python.org/view/python/trunk/Modules/timemodule.c?revision=81756&view=markup

答案 2 :(得分:19)

David的帖子试图显示Windows上的时钟分辨率。我对他的输出感到困惑,所以我写了一些代码,表明我的Windows 8 x64笔记本电脑上的time.time()分辨率为1毫秒:

# measure the smallest time delta by spinning until the time changes
def measure():
    t0 = time.time()
    t1 = t0
    while t1 == t0:
        t1 = time.time()
    return (t0, t1, t1-t0)

samples = [measure() for i in range(10)]

for s in samples:
    print s

哪个输出:

(1390455900.085, 1390455900.086, 0.0009999275207519531)
(1390455900.086, 1390455900.087, 0.0009999275207519531)
(1390455900.087, 1390455900.088, 0.0010001659393310547)
(1390455900.088, 1390455900.089, 0.0009999275207519531)
(1390455900.089, 1390455900.09, 0.0009999275207519531)
(1390455900.09, 1390455900.091, 0.0010001659393310547)
(1390455900.091, 1390455900.092, 0.0009999275207519531)
(1390455900.092, 1390455900.093, 0.0009999275207519531)
(1390455900.093, 1390455900.094, 0.0010001659393310547)
(1390455900.094, 1390455900.095, 0.0009999275207519531)

这是一种平均增量的1000个样本的方法:

reduce( lambda a,b:a+b, [measure()[2] for i in range(1000)], 0.0) / 1000.0

连续两次运行的输出:

0.001
0.0010009999275207519

因此,我的Windows 8 x64上的time.time()分辨率为1毫秒。

time.clock()上的类似运行会返回0.4微秒的分辨率:

def measure_clock():
    t0 = time.clock()
    t1 = time.clock()
    while t1 == t0:
        t1 = time.clock()
    return (t0, t1, t1-t0)

reduce( lambda a,b:a+b, [measure_clock()[2] for i in range(1000000)] )/1000000.0

返回:

4.3571334791658954e-07

哪个是〜0.4e-06

关于time.clock()的一个有趣的事情是,它返回自首次调用方法以来的时间,因此如果您想要微秒分辨率的挂起时间,您可以执行以下操作:

class HighPrecisionWallTime():
    def __init__(self,):
        self._wall_time_0 = time.time()
        self._clock_0 = time.clock()

    def sample(self,):
        dc = time.clock()-self._clock_0
        return self._wall_time_0 + dc

(这可能会在一段时间后漂移,但你偶尔可以纠正这个问题,例如dc > 3600会每小时纠正一次)

答案 3 :(得分:14)

您还可以使用time.clock()它计算Unix上进程使用的时间以及自Windows首次调用它以来的时间。它比time.time()更精确。

这是衡量表现的常用功能。

致电

import time
t_ = time.clock()
#Your code here
print 'Time in function', time.clock() - t_

编辑:Ups,我想念你的问题,因为你想知道时间,而不是花时间......

答案 4 :(得分:7)

如果Python 3是一个选项,您有两种选择:

  • time.perf_counter始终在您的平台上使用最准确的时钟。它确实包括在流程之外花费的时间。
  • time.process_time返回CPU时间。 NOT 包括在流程之外花费的时间。

两者之间的差异可以显示为:

WEB-INF

哪个输出:

from time import (
    process_time,
    perf_counter,
    sleep,
)

print(process_time())
sleep(1)
print(process_time())

print(perf_counter())
sleep(1)
print(perf_counter())

答案 5 :(得分:4)

time.clock()在Windows上有13个小数点,但在Linux上只有两个小数点。 time.time()在Linux上有17位小数,在Windows上有16位小数,但实际精度不同。

我不同意time.clock()应该用于Unix / Linux基准测试的文档。它不够精确,所以使用的计时器取决于操作系统。

在Linux上,时间分辨率在time.time()

中很高
>>> time.time(), time.time()
(1281384913.4374139, 1281384913.4374161)

在Windows上,时间函数似乎使用最后一个被叫号码:

>>> time.time()-int(time.time()), time.time()-int(time.time()), time.time()-time.time()
(0.9570000171661377, 0.9570000171661377, 0.0)

即使我在Windows中的不同行上编写调用,它仍会返回相同的值,因此实际精度较低。

因此,在严格的测量中,必须进行平台检查(import platform, platform.system())才能确定是使用time.clock()还是time.time()

(在Windows 7和Ubuntu 9.10上使用python 2.6和3.1测试)

答案 6 :(得分:4)

Python 3.7引入了6个具有纳秒分辨率的新时间函数,例如代替time.time(),您可以使用time.time_ns()

import time
print(time.time())
# 1522915698.3436284
print(time.time_ns())
# 1522915698343660458

PEP 564

中描述了这6个函数
  

time.clock_gettime_ns(clock_id)

     

time.clock_settime_ns(clock_id, time:int)

     

time.monotonic_ns()

     

time.perf_counter_ns()

     

time.process_time_ns()

     

time.time_ns()

     

这些函数类似于没有_ns后缀的版本,但是   以Python int返回一些纳秒数。

答案 7 :(得分:2)

comment left by tiho on Mar 27 '14 at 17:21应该是它自己的答案:

  

为了避免特定于平台的代码,请使用timeit.default_timer()

答案 8 :(得分:1)

我发现Windows 10专业版和教育版之间的time.time()分辨率不同。

在Windows 10 Professional计算机上,分辨率为1毫秒。 在Windows 10教育版计算机上,分辨率为16毫秒。

幸运的是,有一个工具可以提高Windows中Python的时间分辨率: https://vvvv.org/contribution/windows-system-timer-tool

使用此工具,无论Windows版本如何,我都能实现1 ms的分辨率。在执行Python代码时,您需要使其保持运行状态。

答案 9 :(得分:1)

对于卡在Windows(版本> = Server 2012或Win 8)和python 2.7上的用户,

import ctypes

class FILETIME(ctypes.Structure):
    _fields_ = [("dwLowDateTime", ctypes.c_uint),
                ("dwHighDateTime", ctypes.c_uint)]

def time():
    """Accurate version of time.time() for windows, return UTC time in term of seconds since 01/01/1601
"""
    file_time = FILETIME()
    ctypes.windll.kernel32.GetSystemTimePreciseAsFileTime(ctypes.byref(file_time))
    return (file_time.dwLowDateTime + (file_time.dwHighDateTime << 32)) / 1.0e7

GetSystemTimePreciseAsFileTime function

答案 10 :(得分:1)

以下是Windows的python 3解决方案,它基于 Cyber​​Snoopy 在上面发布的答案(使用 GetSystemTimePreciseAsFileTime )。我们从 jfs

借用了一些代码

Python datetime.utcnow() returning incorrect datetime

并获得精确的时间戳(Unix时间)(以微秒为单位)

#! python3
import ctypes.wintypes

def utcnow_microseconds():
    system_time = ctypes.wintypes.FILETIME()
    #system call used by time.time()
    #ctypes.windll.kernel32.GetSystemTimeAsFileTime(ctypes.byref(system_time))
    #getting high precision:
    ctypes.windll.kernel32.GetSystemTimePreciseAsFileTime(ctypes.byref(system_time))
    large = (system_time.dwHighDateTime << 32) + system_time.dwLowDateTime
    return large // 10 - 11644473600000000

for ii in range(5):
    print(utcnow_microseconds()*1e-6)

参考文献
https://docs.microsoft.com/en-us/windows/win32/sysinfo/time-functions
https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
https://support.microsoft.com/en-us/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime

答案 11 :(得分:0)

最初的问题专门针对Unix,但在Windows上涉及了多个答案,因此Windows上的信息具有误导性。 Windows上的默认计时器分辨率为15.6ms you can verify here.

使用来自cod3monk3y的稍微修改的脚本,我可以证明Windows计时器分辨率默认为〜15毫秒。我正在使用here可用的工具来修改分辨率。

脚本:

import time

# measure the smallest time delta by spinning until the time changes
def measure():
    t0 = time.time()
    t1 = t0
    while t1 == t0:
        t1 = time.time()
    return t1-t0

samples = [measure() for i in range(30)]

for s in samples:
    print(f'time delta: {s:.4f} seconds') 

enter image description here

enter image description here

这些结果收集在运行python 3.7 64位的Windows 10 pro 64位上。

答案 12 :(得分:0)

在使用 “两种不同方法的方法” 的同一个win10 OS系统上,似乎存在一个近似的 “ 500 ns” 时差。如果您关心纳秒级精度,请在下面查看我的代码。

对代码的修改基于用户cod3monk3yKevin S的代码。

操作系统:python 3.7.3 (default, date, time) [MSC v.1915 64 bit (AMD64)]

def measure1(mean):
    for i in range(1, my_range+1):
        x = time.time()

        td = x- samples1[i-1][2]
        if i-1 == 0:
            td = 0
        td = f'{td:.6f}'
        samples1.append((i, td, x))
        mean += float(td)
        print (mean)
        sys.stdout.flush()
        time.sleep(0.001)

    mean = mean/my_range

    return mean

def measure2(nr):
    t0 = time.time()
    t1 = t0
    while t1 == t0:
        t1 = time.time()
    td = t1-t0
    td = f'{td:.6f}'
    return (nr, td, t1, t0)

samples1 = [(0, 0, 0)]
my_range = 10
mean1    = 0.0
mean2    = 0.0

mean1 = measure1(mean1)

for i in samples1: print (i)

print ('...\n\n')

samples2 = [measure2(i) for i in range(11)]

for s in samples2:
    #print(f'time delta: {s:.4f} seconds')
    mean2 += float(s[1])
    print (s)

mean2 = mean2/my_range

print ('\nMean1 : ' f'{mean1:.6f}')
print ('Mean2 : ' f'{mean2:.6f}')

measure1结果:

nr, td, t0
(0, 0, 0)
(1, '0.000000', 1562929696.617988)
(2, '0.002000', 1562929696.6199884)
(3, '0.001001', 1562929696.620989)
(4, '0.001001', 1562929696.62199)
(5, '0.001001', 1562929696.6229906)
(6, '0.001001', 1562929696.6239917)
(7, '0.001001', 1562929696.6249924)
(8, '0.001000', 1562929696.6259928)
(9, '0.001001', 1562929696.6269937)
(10, '0.001001', 1562929696.6279945)
...

measure2结果:

nr, td , t1, t0
(0, '0.000500', 1562929696.6294951, 1562929696.6289947)
(1, '0.000501', 1562929696.6299958, 1562929696.6294951)
(2, '0.000500', 1562929696.6304958, 1562929696.6299958)
(3, '0.000500', 1562929696.6309962, 1562929696.6304958)
(4, '0.000500', 1562929696.6314962, 1562929696.6309962)
(5, '0.000500', 1562929696.6319966, 1562929696.6314962)
(6, '0.000500', 1562929696.632497, 1562929696.6319966)
(7, '0.000500', 1562929696.6329975, 1562929696.632497)
(8, '0.000500', 1562929696.633498, 1562929696.6329975)
(9, '0.000500', 1562929696.6339984, 1562929696.633498)
(10, '0.000500', 1562929696.6344984, 1562929696.6339984)

最终结果:

  

平均值1:0.001001#(measure1函数)

     

平均值2:0.000550#(measure2函数)

答案 13 :(得分:-1)

def start(self):
    sec_arg = 10.0
    cptr = 0
    time_start = time.time()
    time_init = time.time()
    while True:
        cptr += 1
        time_start = time.time()
        time.sleep(((time_init + (sec_arg * cptr)) - time_start ))

        # AND YOUR CODE .......
        t00 = threading.Thread(name='thread_request', target=self.send_request, args=([]))
        t00.start()