High-precision clock in Python
在python中有没有一种高精度的时间测量方法——比一秒钟更精确?我怀疑有一种跨平台的方法可以做到这一点;我对UNIX上的高精度时间很感兴趣,特别是在Sun SPARC机器上运行的Solaris。
时间它似乎能够进行高精度的时间测量,但我不想测量代码片段需要多长时间,而是直接访问时间值。
标准的
1 2 3 | >>> import time >>> time.time() #return seconds from epoch 1261367718.971009 |
python 3.7为提供更高分辨率的
1 2 3 4 5 | >>> import time >>> time.time_ns() 1530228533161016309 >>> time.time_ns() / (10 ** 9) # convert to floating-point seconds 1530228544.0792289 |
python努力使用平台最精确的时间函数来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* 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?)修订版=81756&view=标记)
大卫的帖子试图展示Windows上的时钟分辨率。我对他的输出感到困惑,所以我写了一些代码,显示我的Windows 8 x64笔记本电脑上的
1 2 3 4 5 6 7 8 9 10 11 12 | # 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 |
输出:
1 2 3 4 5 6 7 8 9 10 | (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) |
以及一种对delta进行1000个样本平均的方法:
1 | reduce( lambda a,b:a+b, [measure()[2] for i in range(1000)], 0.0) / 1000.0 |
连续两次运行的输出:
1 2 | 0.001 0.0010009999275207519 |
所以我的Windows8x64上的
在
1 2 3 4 5 6 7 8 | 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 |
返回:
1 | 4.3571334791658954e-07 |
是~EDOCX1[16]
1 2 3 4 5 6 7 8 | 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 |
(过一会儿可能会漂移,但您可以偶尔纠正,例如,
您还可以使用time.clock(),它计算Unix上进程使用的时间和Windows上首次调用该进程以来的时间。它比time.time()更精确。
它是通常用来测量性能的函数。
只要打电话
1 2 3 4 | import time t_ = time.clock() #Your code here print 'Time in function', time.clock() - t_ |
编辑:UPS,我想念你想知道的问题,确切的时间,而不是花在…
如果python 3是一个选项,您有两个选择:
time.perf_counter ,它总是使用您平台上最精确的时钟。它确实包括在过程之外花费的时间。- 返回CPU时间的
time.process_time 。它不包括在过程之外花费的时间。
两者之间的区别可以用以下方式表示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from time import ( process_time, perf_counter, sleep, ) print(process_time()) sleep(1) print(process_time()) print(perf_counter()) sleep(1) print(perf_counter()) |
输出:
1 2 3 4 | 0.03125 0.03125 2.560001310720671e-07 1.0005455362793145 |
python 3.7引入了6个纳秒级分辨率的新时间函数,例如,您可以使用
1 2 3 4 5 | 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() These functions are similar to the version without the _ns suffix, but
return a number of nanoseconds as a Python int.
我不同意在UNIX/Linux上使用
在Linux上,
1 2 | >>> time.time(), time.time() (1281384913.4374139, 1281384913.4374161) |
但是,在Windows上,时间函数似乎使用最后调用的数字:
1 2 | >>> time.time()-int(time.time()), time.time()-int(time.time()), time.time()-time.time() (0.9570000171661377, 0.9570000171661377, 0.0) |
即使我在Windows中将调用写在不同的行上,它仍然返回相同的值,因此实际精度较低。
因此,在严格的测量中,必须进行平台检查(
(使用python 2.6和3.1在Windows7和Ubuntu9.10上测试)
Tiho在3月27日14日17:21发表的评论应该是自己的答案:
In order to avoid platform-specific code, use timeit.default_timer()
对于那些卡在Windows(version>=server 2012或win 8)和python 2.7上的用户,
1 2 3 4 5 6 7 8 9 10 11 12 | 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函数
我注意到Windows10专业版和教育版的time.time()的分辨率不同。
在Windows10专业版计算机上,分辨率为1 ms。在Windows10教育机器上,分辨率为16毫秒。
幸运的是,有一个工具可以在Windows中提高python的时间分辨率:网址:https://vvv.org/contribution/windows-system-timer-tool
使用这个工具,无论Windows版本如何,我都能获得1毫秒的分辨率。在执行Python代码时,需要保持它的运行。
最初的问题是专门针对Unix提出的,但有很多答案涉及到了Windows,因此在Windows上存在误导性信息。Windows上的默认计时器分辨率为15.6ms,您可以在此处验证。
使用cod3Monk3y中稍加修改的脚本,我可以显示Windows计时器默认分辨率为~15毫秒。我正在使用这里可用的工具来修改分辨率。
脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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') |
这些结果是在运行python 3.7 64位的Windows10 Pro 64位上收集的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |