delay()
(以毫秒为单位延迟)和 delayMicroseconds()
函数。阅读其他答案后,我发现它们依赖于time
模块,但 Python 3.3之前的模块完全没有任何保证分辨率的类型,其分辨率难以控制。最被赞的答案在这里引用了Windows分辨率(使用他们的答案),为16毫秒,这比我提供的答案(0.5 微秒分辨率)差32000倍。再次强调,我需要1毫秒和1微秒或类似的分辨率,而不是16000微秒的分辨率。
delay()
(以毫秒为单位延迟)和 delayMicroseconds()
函数。阅读其他答案后,我发现它们依赖于time
模块,但 Python 3.3之前的模块完全没有任何保证分辨率的类型,其分辨率难以控制。最被赞的答案在这里引用了Windows分辨率(使用他们的答案),为16毫秒,这比我提供的答案(0.5 微秒分辨率)差32000倍。再次强调,我需要1毫秒和1微秒或类似的分辨率,而不是16000微秒的分辨率。
2022年8月更新:
在现代的Python 3中,先使用import time
,然后使用time.monotonic_ns()
可能已经足够了。 请参见我对另一个问题的新回答:Python中的高精度时钟。 在2016年我回答这个问题时,使用树莓派上的Python 3.1时,这个功能并不存在。
请参见https://docs.python.org/3/library/time.html#time.monotonic_ns。这是Python 3.7中新增的功能。不过我自己还没有测试过。感谢@HenrikMadsen在他的回答中发布了这个链接here,但他不幸地删除了它。
我仍然需要测试这些新的Python 3.7及其后续版本的函数,以确定它们是否与我下面所做的一样好。
因此,请先尝试这个,并将其与我下面所做的进行比较:
import time
time_ns = time.monotonic_ns()
time.clock_gettime_ns()
。根据其名称,它似乎调用了底层的clock_gettime()
C函数,我在C中使用它来实现nanos()
函数(在这里),并在我的C Unix / Linux库中使用:timinglib.c。
2016年的原始回答:
这是一个完全功能的模块,适用于Linux和Windows,并且与其他所有答案链接在此处不同之处在于它适用于 Python 3.3之前的版本 。所有其他答案在大多数情况下需要Python 3.7或更高版本,在其他情况下需要Python 3.3或更高版本。同样,我的下面的答案适用于任何版本的Python的Windows和Linux,至少可以追溯到Python 3.0左右(我不记得它是否适用于Python 2.7)。
它使用 ctypes 库通过Windows中的.dll“动态链接库”文件或Unix或Linux中的.so“共享对象”库文件在Python中调用C或C ++动态库。
函数和代码示例。
函数包括:
- micros()
- millis()
- delay()
- delayMicroseconds()
从我的eRCaGuy_PyTime存储库下载GS_timing.py
,然后执行以下操作:
import GS_timing
time_ms = GS_timing.millis()
time_us = GS_timing.micros()
GS_timing.delay(10) # delay 10 ms
GS_timing.delayMicroseconds(10000) # delay 10000 us
Python代码模块(在GitHub上为eRCaGuy_PyTime):
"""
GS_timing.py
-create some low-level Arduino-like millis() (milliseconds) and micros()
(microseconds) timing functions for Python
By Gabriel Staples
http://www.ElectricRCAircraftGuy.com
-click "Contact me" at the top of my website to find my email address
Started: 11 July 2016
Updated: 13 Aug 2016
History (newest on top):
20160813 - v0.2.0 created - added Linux compatibility, using ctypes, so that it's compatible with pre-Python 3.3 (for Python 3.3 or later just use the built-in time functions for Linux, shown here: https://docs.python.org/3/library/time.html)
-ex: time.clock_gettime(time.CLOCK_MONOTONIC_RAW)
20160711 - v0.1.0 created - functions work for Windows *only* (via the QPC timer)
References:
WINDOWS:
-personal (C++ code): GS_PCArduino.h
1) Acquiring high-resolution time stamps (Windows)
-https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
2) QueryPerformanceCounter function (Windows)
-https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
3) QueryPerformanceFrequency function (Windows)
-https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
4) LARGE_INTEGER union (Windows)
-https://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx
-*****https://dev59.com/gVLTa4cB1Zd3GeqPcJ9J
absolute-timing-cpu-cycle-count
LINUX:
-https://dev59.com/THM_5IYBdhLWcg3w1G-N
"""
import ctypes, os
#Constants:
VERSION = '0.2.0'
#-------------------------------------------------------------------
#FUNCTIONS:
#-------------------------------------------------------------------
#OS-specific low-level timing functions:
if (os.name=='nt'): #for Windows:
def micros():
"return a timestamp in microseconds (us)"
tics = ctypes.c_int64()
freq = ctypes.c_int64()
#get ticks on the internal ~2MHz QPC clock
ctypes.windll.Kernel32.QueryPerformanceCounter(ctypes.byref(tics))
#get the actual freq. of the internal ~2MHz QPC clock
ctypes.windll.Kernel32.QueryPerformanceFrequency(ctypes.byref(freq))
t_us = tics.value*1e6/freq.value
return t_us
def millis():
"return a timestamp in milliseconds (ms)"
tics = ctypes.c_int64()
freq = ctypes.c_int64()
#get ticks on the internal ~2MHz QPC clock
ctypes.windll.Kernel32.QueryPerformanceCounter(ctypes.byref(tics))
#get the actual freq. of the internal ~2MHz QPC clock
ctypes.windll.Kernel32.QueryPerformanceFrequency(ctypes.byref(freq))
t_ms = tics.value*1e3/freq.value
return t_ms
elif (os.name=='posix'): #for Linux:
#Constants:
CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h> here: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h
#prepare ctype timespec structure of {long, long}
class timespec(ctypes.Structure):
_fields_ =\
[
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
#Configure Python access to the clock_gettime C library, via ctypes:
#Documentation:
#-ctypes.CDLL: https://docs.python.org/3.2/library/ctypes.html
#-librt.so.1 with clock_gettime: https://docs.oracle.com/cd/E36784_01/html/E36873/librt-3lib.html #-
#-Linux clock_gettime(): http://linux.die.net/man/3/clock_gettime
librt = ctypes.CDLL('librt.so.1', use_errno=True)
clock_gettime = librt.clock_gettime
#specify input arguments and types to the C clock_gettime() function
# (int clock_ID, timespec* t)
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
def monotonic_time():
"return a timestamp in seconds (sec)"
t = timespec()
#(Note that clock_gettime() returns 0 for success, or -1 for failure, in
# which case errno is set appropriately)
#-see here: http://linux.die.net/man/3/clock_gettime
if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0:
#if clock_gettime() returns an error
errno_ = ctypes.get_errno()
raise OSError(errno_, os.strerror(errno_))
return t.tv_sec + t.tv_nsec*1e-9 #sec
def micros():
"return a timestamp in microseconds (us)"
return monotonic_time()*1e6 #us
def millis():
"return a timestamp in milliseconds (ms)"
return monotonic_time()*1e3 #ms
#Other timing functions:
def delay(delay_ms):
"delay for delay_ms milliseconds (ms)"
t_start = millis()
while (millis() - t_start < delay_ms):
pass #do nothing
return
def delayMicroseconds(delay_us):
"delay for delay_us microseconds (us)"
t_start = micros()
while (micros() - t_start < delay_us):
pass #do nothing
return
#-------------------------------------------------------------------
#EXAMPLES:
#-------------------------------------------------------------------
#Only executute this block of code if running this module directly,
#*not* if importing it
#-see here: http://effbot.org/pyfaq/tutor-what-is-if-name-main-for.htm
if __name__ == "__main__": #if running this module as a stand-alone program
#print loop execution time 100 times, using micros()
tStart = micros() #us
for x in range(0, 100):
tNow = micros() #us
dt = tNow - tStart #us; delta time
tStart = tNow #us; update
print("dt(us) = " + str(dt))
#print loop execution time 100 times, using millis()
print("\n")
tStart = millis() #ms
for x in range(0, 100):
tNow = millis() #ms
dt = tNow - tStart #ms; delta time
tStart = tNow #ms; update
print("dt(ms) = " + str(dt))
#print a counter once per second, for 5 seconds, using delay
print("\nstart")
for i in range(1,6):
delay(1000)
print(i)
#print a counter once per second, for 5 seconds, using delayMicroseconds
print("\nstart")
for i in range(1,6):
delayMicroseconds(1000000)
print(i)
如果您知道如何在Linux中获取上述毫秒和微秒分辨率的时间戳,请发布,因为那将非常有帮助。
这也适用于Linux,包括Python 3.3之前的版本,因为我使用ctypes模块通过C函数读取时间戳。
(注意:以上代码最初发布在此处:http://www.electricrcaircraftguy.com/2016/07/arduino-like-millisecond-and-microsecond-timestamps-in-python.html)
特别感谢@ArminRonacher在此处提供的Python 3.3之前Linux的杰出答案:https://dev59.com/THM_5IYBdhLWcg3w1G-N#1205762
时间戳和时钟参考:
- Windows:
QueryPerformanceCounter()
: https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter:
检索性能计数器的当前值,该计数器是一个高分辨率(<1us)时间戳,可用于时间间隔测量。
- Linux:
clock_gettime()
: https://man7.org/linux/man-pages/man3/clock_gettime.3.html (强调添加):
CLOCK_MONOTONIC
表示自某个未指定的时间点以来的单调时间的不可设置系统范围时钟。在Linux上,该点对应于系统自启动以来运行的秒数。
CLOCK_MONOTONIC_RAW
(since Linux 2.6.28; 仅限Linux)
类似于CLOCK_MONOTONIC
,但提供对未经NTP调整或由adjtime(3)
执行的增量调整不受影响的原始基于硬件的时间的访问。此时钟不计算系统挂起的时间。
- 请注意,两个系统上的两个时钟均不提供“墙钟”类型的时间戳。相反,它们都提供高分辨率(亚微秒)时间戳,通常计算自启动以来的时间。这些时间戳可用于精确测量事件的时间、生成可重复的周期循环以及在代码中测量小的时间间隔,具有极高的分辨率、精度和准确性。
更新:在 Python 3.3 之前,内置的 Python 时间库(https://docs.python.org/3.5/library/time.html)没有任何显式的高分辨率函数。然而,现在它提供了其他选项,包括一些高分辨率函数。
然而,我的模块为 Python 3.3 之前和之后的代码提供了高分辨率时间戳,并且在 Linux 和 Windows 上都能实现,而且。
这里是一个例子,展示了 time.sleep()
函数不一定是高分辨率函数。在我的 Windows 机器上,它的分辨率可能最多只有8毫秒,而我的模块在同一台机器上具有0.5微秒的分辨率(比原来好了16000倍!)。
代码演示:
import time
import GS_timing as timing
def delayMicroseconds(n):
time.sleep(n / 1000000.)
def delayMillisecond(n):
time.sleep(n / 1000.)
t_start = 0
t_end = 0
#using time.sleep
print('using time.sleep')
print('delayMicroseconds(1)')
for x in range(10):
t_start = timing.micros() #us
delayMicroseconds(1)
t_end = timing.micros() #us
print('dt (us) = ' + str(t_end - t_start))
print('delayMicroseconds(2000)')
for x in range(10):
t_start = timing.micros() #us
delayMicroseconds(2000)
t_end = timing.micros() #us
print('dt (us) = ' + str(t_end - t_start))
#using GS_timing
print('\nusing GS_timing')
print('timing.delayMicroseconds(1)')
for x in range(10):
t_start = timing.micros() #us
timing.delayMicroseconds(1)
t_end = timing.micros() #us
print('dt (us) = ' + str(t_end - t_start))
print('timing.delayMicroseconds(2000)')
for x in range(10):
t_start = timing.micros() #us
timing.delayMicroseconds(2000)
t_end = timing.micros() #us
print('dt (us) = ' + str(t_end - t_start))
我的Windows 8.1电脑的样本结果(注意time.sleep的表现更差):
using time.sleep
delayMicroseconds(1)
dt (us) = 2872.059814453125
dt (us) = 886.3939208984375
dt (us) = 770.4649658203125
dt (us) = 1138.7698974609375
dt (us) = 1426.027099609375
dt (us) = 734.557861328125
dt (us) = 10617.233642578125
dt (us) = 9594.90576171875
dt (us) = 9155.299560546875
dt (us) = 9520.526611328125
delayMicroseconds(2000)
dt (us) = 8799.3056640625
dt (us) = 9609.2685546875
dt (us) = 9679.5439453125
dt (us) = 9248.145263671875
dt (us) = 9389.721923828125
dt (us) = 9637.994262695312
dt (us) = 9616.450073242188
dt (us) = 9592.853881835938
dt (us) = 9465.639892578125
dt (us) = 7650.276611328125
using GS_timing
timing.delayMicroseconds(1)
dt (us) = 53.3477783203125
dt (us) = 36.93310546875
dt (us) = 36.9329833984375
dt (us) = 34.8812255859375
dt (us) = 35.3941650390625
dt (us) = 40.010986328125
dt (us) = 38.4720458984375
dt (us) = 56.425537109375
dt (us) = 35.9072265625
dt (us) = 36.420166015625
timing.delayMicroseconds(2000)
dt (us) = 2039.526611328125
dt (us) = 2046.195068359375
dt (us) = 2033.8841552734375
dt (us) = 2037.4747314453125
dt (us) = 2032.34521484375
dt (us) = 2086.2059326171875
dt (us) = 2035.4229736328125
dt (us) = 2051.32470703125
dt (us) = 2040.03955078125
dt (us) = 2027.215576171875
在我的树莓派1B+上进行的样本结果(请注意,使用time.sleep和我的模块之间的结果基本相同...显然,time
中的低级函数已经访问了更好的分辨率计时器,因为它是运行Raspbian的Linux机器...但是,在我的GS_timing
模块中,我明确调用了CLOCK_MONOTONIC_RAW计时器。否则将使用什么计时器无从得知):
using time.sleep
delayMicroseconds(1)
dt (us) = 1022.0
dt (us) = 417.0
dt (us) = 407.0
dt (us) = 450.0
dt (us) = 2078.0
dt (us) = 393.0
dt (us) = 1297.0
dt (us) = 878.0
dt (us) = 1135.0
dt (us) = 2896.0
delayMicroseconds(2000)
dt (us) = 2746.0
dt (us) = 2568.0
dt (us) = 2512.0
dt (us) = 2423.0
dt (us) = 2454.0
dt (us) = 2608.0
dt (us) = 2518.0
dt (us) = 2569.0
dt (us) = 2548.0
dt (us) = 2496.0
using GS_timing
timing.delayMicroseconds(1)
dt (us) = 572.0
dt (us) = 673.0
dt (us) = 1084.0
dt (us) = 561.0
dt (us) = 728.0
dt (us) = 576.0
dt (us) = 556.0
dt (us) = 584.0
dt (us) = 576.0
dt (us) = 578.0
timing.delayMicroseconds(2000)
dt (us) = 2741.0
dt (us) = 2466.0
dt (us) = 2522.0
dt (us) = 2810.0
dt (us) = 2589.0
dt (us) = 2681.0
dt (us) = 2546.0
dt (us) = 3090.0
dt (us) = 2600.0
dt (us) = 2400.0
相关:
- 我的3个时间戳函数集(相互交叉链接):
- 关于C时间戳,请参见我在这里的答案:Get a timestamp in C in microseconds?
- 关于C++高分辨率时间戳,请参见我在这里的答案:Getting an accurate execution time in C++ (micro seconds)
- 关于Python高分辨率时间戳,请参见我在这里的答案:How can I get millisecond and microsecond-resolution timestamps in Python?
- 我的C和C++ Linux高分辨率计时库,包括
millis()
、micros()
、nanos()
、sleep_ns()
、sleep_until_ns
、use_realtime_scheduler()
、get_estimated_resolution()
等。
- [我的C和C++答案,包括微控制器(或任何其他系统)] How to do timestamp-based, non-blocking, single-threaded cooperative multi-tasking
- [我的C和C++答案,包括微控制器和Arduino(或任何其他系统)] Full coulomb counter example demonstrating the above concept with timestamp-based, single-threaded, cooperative multi-tasking
- [我的C和C++答案,在Linux中--可以使用
ctypes
模块轻松适应Python,如上所示] How to run a high-resolution, high-precision periodic loop in Linux easily, at any frequency (ex: up to 10 KHz~100 KHz) using a soft real-time scheduler and nanosecond delays
import time
后跟time.monotonic_ns()
可能已经足够了。在我回答的时候,这还不存在。请参见https://docs.python.org/3/library/time.html#time.monotonic_ns。这是Python 3.7中的新功能。不过我自己还没有测试过。感谢@HenrikMadsen在他的答案中发布了这个问题(https://stackoverflow.com/a/68486952/4561887),但很遗憾他已经删除了它。 - Gabriel Staplesimport time
def delayMicroseconds(n):
time.sleep(n / 1000000.)
def delayMillisecond(n):
time.sleep(n / 1000.)
另请参阅:如何在Python中进行时间延迟?
time
库。嗯……这并不是那么简单。如果你阅读了时间文档 (https://docs.python.org/3.5/library/time.html) ,你也会看到在 Python 3.3 发布时对内置 Python 库进行了一些 重大 更改,但我的树莓派只有 Python 3.2.3,并且显示它是最新版本,所以我必须定制一些东西来确保我得到想要的东西。例如:CLOCK_MONOTONIC_RAW
。 - Gabriel Staples
time.perf_counter
,它在Windows上使用了QueryPerformanceCounter
。 - Karl Knechtel